pax_global_header00006660000000000000000000000064150640547150014521gustar00rootroot0000000000000052 comment=9707aa9fde6d24fcfd6f0be01ebefd9f74f08ced tpm2-pytss-3.0.0-rc0/000077500000000000000000000000001506405471500142455ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/.ci/000077500000000000000000000000001506405471500147165ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/.ci/install-deps.sh000077500000000000000000000053141506405471500176570ustar00rootroot00000000000000#!/usr/bin/env bash # SPDX-License-Identifier: BSD-2-Clause set -exo pipefail export TPM2_TSS_VERSION=${TPM2_TSS_VERSION:-"3.0.3"} export TPM2_TSS_FAPI=${TPM2_TSS_FAPI:-"true"} # # Get dependencies for building and install tpm2-tss and abrmd projects # sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \ autoconf-archive \ curl \ libcmocka0 \ libcmocka-dev \ net-tools \ build-essential \ git \ pkg-config \ gcc \ g++ \ m4 \ libtool \ automake \ libgcrypt20-dev \ libssl-dev \ autoconf \ gnulib \ wget \ doxygen \ lcov \ libcurl4-openssl-dev \ expect \ gawk \ libjson-c-dev \ uuid-dev \ gnutls-bin \ acl \ libtasn1-6-dev \ socat \ libseccomp-dev \ libjson-glib-dev \ libltdl-dev # # Install tpm2-tss # if ! pkg-config tss2-sys; then # for git describe to work, one needs either a tag or a deep clone of master. if [ "${TPM2_TSS_VERSION}" != "master" ]; then tpm2_tss2_extra_git_flags="--depth 1" fi git -C /tmp clone ${tpm2_tss2_extra_git_flags} \ --branch "${TPM2_TSS_VERSION}" https://github.com/tpm2-software/tpm2-tss.git pushd /tmp/tpm2-tss if [ "${TPM2_TSS_FAPI}" != "true" ]; then extra_configure_flags="--disable-fapi" fi ./bootstrap ./configure --sysconfdir=/etc ${extra_configure_flags} CFLAGS=-g make -j4 sudo make install sudo ldconfig popd fi # # Get a simulator # # Does our tcti support the TCTI for swtpm? If so get the swtpm simulator if pkg-config --exists tss2-tcti-swtpm; then # libtpms if ! pkg-config libtpms; then git -C /tmp clone --depth=1 https://github.com/stefanberger/libtpms.git pushd /tmp/libtpms ./autogen.sh --prefix=/usr --with-openssl --with-tpm2 --without-tpm1 make -j$(nproc) sudo make install popd rm -fr /tmp/libtpms sudo ldconfig fi # swtpm if ! command -v swtpm; then git -C /tmp clone --depth=1 https://github.com/stefanberger/swtpm.git pushd /tmp/swtpm ./autogen.sh --prefix=/usr make -j$(nproc) sudo make install popd rm -fr /tmp/swtpm fi # Get IBM Simulator (supported for a longer time) else # pull from fork that has fixes for RC handling not yet in mainline. git -C /tmp clone --depth=1 https://github.com/kgoldman/ibmswtpm2.git pushd /tmp/ibmswtpm2/src make -j$(nproc) sudo cp tpm_server /usr/local/bin popd rm -fr /tmp/ibmswtpm2 fi # # Pip version 21.3 was broken with in-pace (-e) installs. Thus use something # after it as it was fixed in 21.3.1 # python3 -m pip install --user --upgrade 'pip>21.3' # # Install Python Development Dependencies # python3 -m pip install --user -e .[dev] exit 0 tpm2-pytss-3.0.0-rc0/.ci/run.sh000077500000000000000000000063011506405471500160610ustar00rootroot00000000000000#!/usr/bin/env bash set -ex if [ -d "${HOME}/.local/bin" ]; then export PATH="${HOME}/.local/bin:${PATH}" fi SRC_ROOT=${SRC_ROOT:-"${PWD}"} PYTHON=${PYTHON:-"python3"} function run_publish_pkg() { if [ "x${GITHUB_ACTIONS}" != "xtrue" ]; then echo "Did not detect github actions, exiting." exit 1 fi if [[ "x${GITHUB_REF}" != "xrefs/tags/"* ]]; then echo "Did not detect TAG, got ${GITHUB_REF}." echo "exiting." exit 1 fi git status git reset --hard HEAD git clean -xdf pypi_version=$(python -c 'import json, urllib.request; print(json.loads(urllib.request.urlopen("https://pypi.org/pypi/tpm2-pytss/json").read())["info"]["version"])') tag=${GITHUB_REF/refs\/tags\//} if [ "x${tag}" == "x${pypi_version}" ]; then echo "Git Tag is same as PyPI version: ${tag} == ${pypi_version}" echo "Nothing to do, exiting." exit 0 fi # get the dependencies from setup.cfg and install them python3 -c "import configparser; c = configparser.ConfigParser(); c.read('setup.cfg'); print(c['options']['install_requires'])" | \ xargs pip install python3 -c "import configparser; c = configparser.ConfigParser(); c.read('setup.cfg'); print(c['options']['setup_requires'])" | \ xargs pip install python setup.py sdist python -m twine upload dist/* } function run_test() { # installs the deps so sdist and bdist work. python3 -m pip install wheel $(./scripts/get_deps.py) python3 setup.py sdist && python3 setup.py bdist python3 -m pytest -n $(nproc) --cov=tpm2_pytss -v if [ -n "${ENABLE_COVERAGE}" ]; then python3 -m coverage xml -o /tmp/coverage.xml fi # verify that package is sane on a user install that is not editable git clean -fdx python3 -m pip install --user . # can't be in a directory that has the package as a folder, Python tries to use that # over whats installed. pushd /tmp python3 -c 'import tpm2_pytss' popd # verify wheel build works git clean -fdx python3 -m pip uninstall --yes tpm2-pytss python3 -Bm build --no-isolation python3 -m installer --destdir=installation dist/*.whl # find site-packages site_packages=$(realpath $(find . -type d -name site-packages)) export PYTHONPATH="${site_packages}" totest=$(realpath test/test_esapi.py) pushd /tmp # ensure module imports OK python3 -c 'import tpm2_pytss' # ensure a test suite can run, but don't run the whole thing and slow down the CI since # we already ran the tests. pytest "$totest" -k test_get_random popd } function run_whitespace() { export whitespace=$(mktemp -u) function rmtempfile () { rm -f "$whitespace" } trap rmtempfile EXIT find . -type f -name '*.py' -exec grep -EHn " +$" {} \; 2>&1 > "$whitespace" lines=$(wc -l < "$whitespace") if [ "$lines" -ne 0 ]; then echo "Trailing whitespace found" >&2 cat "${whitespace}" >&2 exit 1 fi } function run_style() { "${PYTHON}" -m black --diff --check "${SRC_ROOT}" } function run_lint() { ruff check "${SRC_ROOT}" } if [ "x${TEST}" != "x" ]; then run_test elif [ "x${WHITESPACE}" != "x" ]; then run_whitespace elif [ "x${STYLE}" != "x" ]; then run_style elif [ "x${PUBLISH_PKG}" != "x" ]; then run_publish_pkg elif [ "x${LINT}" != "x" ]; then run_lint fi tpm2-pytss-3.0.0-rc0/.coveragerc000066400000000000000000000003331506405471500163650ustar00rootroot00000000000000[run] branch = True source = tpm2-pytss [report] exclude_lines = if self.debug: pragma: no cover raise NotImplementedError if __name__ == .__main__.: ignore_errors = True omit = test/* setup.py tpm2-pytss-3.0.0-rc0/.github/000077500000000000000000000000001506405471500156055ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/.github/codeql.yml000066400000000000000000000000721506405471500175760ustar00rootroot00000000000000query-filters: - exclude: id: py/polluting-import tpm2-pytss-3.0.0-rc0/.github/dependabot.yml000066400000000000000000000007641506405471500204440ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" tpm2-pytss-3.0.0-rc0/.github/workflows/000077500000000000000000000000001506405471500176425ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/.github/workflows/codeql.yml000066400000000000000000000015611506405471500216370ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [ "master" ] pull_request: branches: [ "master" ] schedule: - cron: "16 8 * * 5" jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ python ] steps: - name: Checkout uses: actions/checkout@v3 - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql.yml queries: +security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" tpm2-pytss-3.0.0-rc0/.github/workflows/daily.yaml000066400000000000000000000010071506405471500216260ustar00rootroot00000000000000name: Daily Test on: schedule: - cron: '0 3 * * *' jobs: test: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: 3.x - name: Install dependencies env: TPM2_TSS_VERSION: "master" TPM2_TSS_FAPI: true run: ./.ci/install-deps.sh - name: Check env: TEST: 1 run: ./.ci/run.sh tpm2-pytss-3.0.0-rc0/.github/workflows/publish_pkg.yaml000066400000000000000000000013671506405471500230440ustar00rootroot00000000000000name: Publish PyPI Package on: push: tags: - '*' jobs: publish: runs-on: ubuntu-20.04 steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Set up Python 3.8 uses: actions/setup-python@v2 with: python-version: 3.8 - name: Install Dependencies env: TPM2_TSS_VERSION: 3.0.0 run: | python3 -m pip install --user --upgrade pip python3 -m pip install --user --upgrade twine ./.ci/install-deps.sh - name: Test env: TEST: 1 run: ./.ci/run.sh - name: Publish to PyPi env: PUBLISH_PKG: 1 TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TPM2_PYTSS }} run: ./.ci/run.sh tpm2-pytss-3.0.0-rc0/.github/workflows/tests.yaml000066400000000000000000000047671506405471500217060ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] tss-version: ['master', '3.2.3', '4.0.2', '4.1.3'] with-fapi: [true] include: - python-version: '3.9' tss-version: '3.2.3' with-fapi: false steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies env: TPM2_TSS_VERSION: ${{ matrix.tss-version }} TPM2_TSS_FAPI: ${{ matrix.with-fapi }} TPM2_TOOLS_VERSION: ${{ matrix.tools-version }} run: ./.ci/install-deps.sh - name: Check env: TEST: 1 run: ./.ci/run.sh coverage: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Set up Python 3.x uses: actions/setup-python@v2 with: python-version: 3.x - name: Install dependencies env: TPM2_TSS_VERSION: 4.1.3 run: ./.ci/install-deps.sh - name: Check env: TEST: 1 ENABLE_COVERAGE: true run: ./.ci/run.sh - name: Upload coverage report uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: /tmp/coverage.xml whitespace-check: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Check env: WHITESPACE: 1 run: ./.ci/run.sh style-check: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Install Dependencies run: | python3 -m pip install --user --break-system-packages --upgrade pip python3 -m pip install --user --break-system-packages --upgrade black~=24.0 - name: Check env: STYLE: 1 run: ./.ci/run.sh lint: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Install Dependencies run: | python3 -m pip install --user --break-system-packages --upgrade pip python3 -m pip install --user --break-system-packages --upgrade ruff - name: Check env: LINT: 1 run: ./.ci/run.sh tpm2-pytss-3.0.0-rc0/.gitignore000066400000000000000000000007401506405471500162360ustar00rootroot00000000000000*.swp Makefile.in *.so *.o *~ aclocal.m4 autom4te.cache/ compile config.guess config.sub configure depcomp install-sh ltmain.sh m4/ missing *wrap.c Makefile config.log config.status libtool test-driver test-suite.log test/*.log test/*.trs __pycache__/ *.pyc *.egg-info/ **/*_binding.py !tests/*_binding.py NVChip build/ dist/ docs/build/ pages/ public/ *.h .coverage *.orig *.rej htmlcov /.pytest_cache/ src/tpm2_pytss/internal/type_mapping.py src/tpm2_pytss/internal/versions.py tpm2-pytss-3.0.0-rc0/.gitmodules000066400000000000000000000000001506405471500164100ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/.readthedocs.yml000066400000000000000000000004431506405471500173340ustar00rootroot00000000000000# Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 build: os: ubuntu-22.04 tools: python: "3" sphinx: builder: html configuration: docs/conf.py python: install: - requirements: docs/requirements.txt tpm2-pytss-3.0.0-rc0/CHANGELOG.md000066400000000000000000000146351506405471500160670ustar00rootroot00000000000000# 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). ## 3.0.0-rc0 - 2025-09-21 ### Fixed - Restore environment when exiting FAPIConfig ### Added - Add a context manager for ESYS handles, which flushes the handle at exit. - Add SVN, ACT and other missing constants. - Add the ESAPI command `certify_x509`. - Add the ESAPI command `act_set_timeout`. - Add copy dunder for cryptography private keys. - Add the ESAPI command `trsess_get_attributes`. - Add signature scheme structures. - Add marshal/unmarshal structures for `TPM2_HANDLE`. - Add the command_parser module, which can decode TPM 2.0 command/response byte streams. - Add support for passing prehashed data to `TPMT_SIGNATURE.verify_signature`. - Add the marshal/unmarshal methods to union types, as they require a selector. - Add the equal dunder to struct types, allowing comparing two different instances of the same type. ### Changed - Make the symmetric argument to `start_auth_session` optional. - Accept None for the pcr_digest argument for `policy_pcr`. - Support looking up EK templates by other names, such as `L-1` or `H-2`. - Make the validition ticket for the sign command optional, defaults to a NULL ticket. - The argument order for `ESAPI.policy_signed`, `ESAPI.policy_ticket` and `ESAPI.policy_authorize` has changed. This is to make expiration, nonce_tpm, policy_ref and cp_hash_a arguments optional, with expiration being set to the max value and the rest are empty buffers by default. ### Removed - Remove support for the tools encoder/decoder. ## 2.3.0 - 2024-06-26 ### Fixed - Fix builds for tpm2-tss > 4.0.1. - Support newer releases of the cryptography package. ### Added - Add module to use TPM keys with the cryptography package. - Support for exists_ok for FAPI.create_nv, behaves the same as for FAPI.create_key. ### Changed - Support for the tpm2-tools encoder/decoder will be removed in the future and a warning has been added. ## 2.2.1 - 2024-01-07 ### Fixed - Fix tests `pcr_set_auth_value` and `pcr_set_auth_policy` tests when running against libtpms-based simulators. - Fix integration with cryptography >= 42.0.1 ## 2.2.0 - 2023-11-30 ### Fixed - Fix pycparse error for __float128. - Fix check on ESYS_TR in policy_secret. - Fix readthedocs builds. - Fix hardcoded sizes in the policy module. ### Added - Add routine for making ESYS_TR from parts. - Support unmarshal and marshal routines for constants. - Provide a better error message for missing symbols. - Add support for python 3.12. ### Removed - Drop support for python 3.7. - Remove references to TPMS_ALGORITHM_DESCRIPTION. ## 2.1.0 - 2022-01-09 ### Fixed - using tpm2-pytss in unit tests within a mocked environment see #481. ### Added - tpm2-tools like strings via parse for TPM2_SYM_DEF and TPM2_SYM_DEF_OBJECT structures. - support for algorithms strings in ESAPI start_auth_session. - utils: credential_to_tools and tools_to_credential to convert to and from tpm2-tools makecredential outputs. - TCTI: Add bindings to TCTISpiHelper. ## 2.0.0 - 2022-12-05 ### Fixed - Resolution of include directory search paths when building CFFI bindings. - Typo in pip package name in README. - Missing package pycparser dependency in setup.cfg. - Minimum version of tss2-esys as 2.4.0. - Reproducible documentation builds using `SOURCE_DATE_EPOCH`. See #376. - documentation issues, such as cross linking, indentation and style. - test/test_utils.py::TestUtils::test_make_credential_ecc_camellia when CAMELLIA is not supported. - Stop leaking tpm simulator references in test harness. - Limitation on 10 set policy callbacks, now has no hard limit, see #473 ### Added - **Experimental** bindings to the policy library tss2-policy. Require version 3.3+ of tpm2-tss to enable. - Support for Python 3.11. - Testing on CI for built wheel. - PyTCTI class for writing Python Native TCTIs. ### Changed - TCTI get\_poll\_handles now returning PollData object instead of ffi.CData. - TCTI magic is now byte string eg b"\x1" of up to 8 bytes. ## 1.2.0 - 2022-06-14 ### Added - utils function to parse tpm2-tools PCR values as function: unmarshal_tools_pcr_values. - official python 3.10 support. - sm2 and sm4 tools like parsing support for TPMT_PUBLIC and TPM2B_PUBLIC structures. - tpm2-tools compatible YAML encoding and decoding of TPM structures ### Removed - pkgconfig as runtime dependency - Official Python 3.6 support. - internal distutils usage. - sm3 and sm4 support IF the backing cryptography package supports it. ### Fixed: - trsess_set_attributes attributes parameter should be a TPMA_SESSION or int, not just int. - setup.cfg install_requires requirement that cryptography be version 3.0 or greater. - Note in documentation incorrectly called None. - ability to build a wheel and run tests from directory root. Note code for package is now under src folder. ## 1.1.0 - 2022-03-29 ### Fixed - Spelling of "Enhanced" in CHANGELOG for 1.0.0 release. - Ensure that TPM2_GENERATED.VALUE is encoded the same way as other constants. - Add support to unmarshal simple TPM2B types (such as TPM2B_ATTEST and TPM2B_NAME) directly using the unmarshal method - utils: catch the ImportError as "e" enabling raising the exception later - types: add check in TPMS_CONTEXT.to_tools for session handles ### Changed - Drop pkgconfig from runtime dependencies, thus no longer need dev packages of built bindings at runtime. - NOTE: Version information is cached, a change in the TSS libraries requires a rebuild of the bindings. ### Added - Support session contexts from tpm2-tools as well as function to marshal context to tpm2-tools format. - Support two new encoding/decoding classes to go to/from hex or json representation of objects. - Support for creating EK from templates and optionally NV index based templates. - Binding to `Esys_TR_GetTpmHandle` as `ESAPI` method `tr_get_tpm_handle`. ## [1.0.0] - 2022-01-24 ### Added - Bindings to the Enhanced System (ESAPI) API. - Bindings to the Feature (FAPI) API . - Bindings to Dynamic TCTI Loading (TCTILdr) API . - Bindings to Marshalling and Unmarshalling (MU) API. - Bindings to rc-decode. - tpm2-tools context file loading support. - TSS2 PEM format support. This file format is used in OpenSSL Engine and Provider projects. - Utility routines for: TPM Less Make Credential, sensitive wrapping and unwrapping (import and duplication helpers). tpm2-pytss-3.0.0-rc0/LICENSE000066400000000000000000000023241506405471500152530ustar00rootroot00000000000000Redistribution 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. 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. tpm2-pytss-3.0.0-rc0/MANIFEST.in000066400000000000000000000003631506405471500160050ustar00rootroot00000000000000include README.md include LICENSE include src/tpm2_pytss/version include src/tpm2_pytss/config.json recursive-include src/tpm2_pytss/swig * recursive-include tests * recursive-include examples * exclude src/tpm2_pytss/internal/type_mapping.py tpm2-pytss-3.0.0-rc0/README.md000066400000000000000000000045061506405471500155310ustar00rootroot00000000000000# tpm2-pytss [![Tests](https://github.com/tpm2-software/tpm2-pytss/actions/workflows/tests.yaml/badge.svg)](https://github.com/tpm2-software/tpm2-pytss/actions/workflows/tests.yaml) [![codecov](https://codecov.io/gh/tpm2-software/tpm2-pytss/branch/master/graph/badge.svg?token=Nqs8anZr2B)](https://codecov.io/gh/tpm2-software/tpm2-pytss) [![Documentation Status](https://readthedocs.org/projects/tpm2-pytss/badge/?version=latest)](https://tpm2-pytss.readthedocs.io/en/latest/?badge=latest) [![CodeQL](https://github.com/tpm2-software/tpm2-pytss/actions/workflows/codeql.yml/badge.svg?branch=master&event=push)](https://github.com/tpm2-software/tpm2-pytss/actions/workflows/codeql.yml) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black) [![PyPI version](https://img.shields.io/pypi/v/tpm2-pytss.svg)](https://pypi.org/project/tpm2-pytss) TPM2 TSS Python bindings for Enhanced System API (ESYS), Feature API (FAPI), Marshaling (MU), TCTI Loader (TCTILdr), TCTIs, policy, and RC Decoding (rcdecode) libraries. It allows for custom TCTIs written in Python as well. It also contains utility methods for wrapping keys to TPM 2.0 data structures for importation into the TPM, unwrapping keys and exporting them from the TPM, TPM-less makecredential command and name calculations, TSS2 PEM Key format support, importing Keys from PEM, DER and SSH formats, conversion from tpm2-tools based command line strings and loading tpm2-tools context files. ## Documentation Documentation for the latest release is hosted at https://tpm2-pytss.readthedocs.io/en/latest/index.html ## Installing To install the master branch: ```bash python3 -m pip install git+https://github.com/tpm2-software/tpm2-pytss.git ``` To install latest stable from PyPi: ```bash python3 -m pip install tpm2-pytss ``` **NOTE**: You may need option `--user` or sitewide permissions through something like `sudo`. This is known to work with versions 2.4.0 of tpm2-tss or higher. ## Help - Ask a question via an [issue](https://github.com/tpm2-software/tpm2-pytss/issues/new) - Send an email to the tpm2 list: - https://lists.linuxfoundation.org/mailman/listinfo/tpm2 - File a Security Bug by following the instructions in [docs/SECURITY.md](docs/SECURITY.md) ## License tpm2-pytss is distributed under the [BSD 2 Clause License](LICENSE). tpm2-pytss-3.0.0-rc0/docs/000077500000000000000000000000001506405471500151755ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/docs/CODE_OF_CONDUCT.md000066400000000000000000000125711506405471500200020ustar00rootroot00000000000000 # 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.rst). 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 tpm2-pytss-3.0.0-rc0/docs/SECURITY.md000066400000000000000000000030361506405471500167700ustar00rootroot00000000000000# 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: - 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: - 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. tpm2-pytss-3.0.0-rc0/docs/_static/000077500000000000000000000000001506405471500166235ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/docs/_static/.gitkeep000066400000000000000000000000001506405471500202420ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/docs/api.rst000066400000000000000000000006221506405471500165000ustar00rootroot00000000000000API ========== The API documentation for the tpm2-pytss project. .. toctree:: TPM Constants TPM Types TPM Command Transmission Interface (TCTI) Enhanced System API (ESAPI) Feature API (FAPI) Policy Utility Routines TSS PEM Key (OpenSSL) TSS2_Exception cryptography tpm2-pytss-3.0.0-rc0/docs/conf.py000066400000000000000000000122241506405471500164750ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import sys import time import datetime import subprocess from setuptools_scm import get_version from sphinx.util import logging logger = logging.getLogger(__name__) class FakeVersions: _versions = { "tss2-esys": "255.255.255", "tss2-fapi": "255.255.255", "tss2-policy": "255.255.255", "tss2-tcti-spi-helper": "255.255.255", } if os.environ.get("READTHEDOCS", False): import git logger.info("READTHEDOCS DETECTED") cwd = os.getcwd() repo = git.Repo(cwd, search_parent_directories=True) root = repo.git.rev_parse("--show-toplevel") logger.info(f"Adding to PATH: {root}") path = os.path.join(root, "src") sys.path.insert(0, path) l = os.listdir(path) logger.info(f"{path} ls: {l}") sys.modules["tpm2_pytss.internal.versions"] = FakeVersions logger.info("Mocking tpm2_pytss._libtpm2_pytss") from unittest.mock import MagicMock class MyMagicMock(MagicMock): def __repr__(self): name = self._extract_mock_name() name = name.replace("mock.lib.", "") if name.startswith("ESYS_TR_"): end = name.replace("ESYS_TR_", "") name = "ESYS_TR." + end return name sys.modules["tpm2_pytss._libtpm2_pytss"] = MyMagicMock() # -- Project information ----------------------------------------------------- project = "tpm2-pytss" author = "tpm2-software" build_date = datetime.datetime.utcfromtimestamp( int(os.environ.get("SOURCE_DATE_EPOCH", time.time())) ) copyright = f"2019 - {build_date.year}, {author}" # The short X.Y version version = get_version(root="..", relative_to=__file__) # The full version, including alpha/beta/rc tags release = get_version(root="..", relative_to=__file__) # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", "sphinx.ext.autosectionlabel", "myst_parser", ] source_suffix = { ".rst": "restructuredtext", ".md": "markdown", } # Autodoc settings autodoc_typehints = "none" intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "cryptography": ("https://cryptography.io/en/latest", None), } autosectionlabel_prefix_document = True autosectionlabel_maxdepth = 1 # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "alabaster" # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # The Read the Docs theme is available from # - https://github.com/snide/sphinx_rtd_theme # - https://pypi.python.org/pypi/sphinx_rtd_theme # - python-sphinx-rtd-theme package (on Debian) try: import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except ImportError: sys.stderr.write( "Warning: The Sphinx 'sphinx_rtd_theme' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n" ) # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] # -- Extension configuration ------------------------------------------------- # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] def builder_finished_handler(app, exception): if exception is None: os.environ["SPHINX_OUTDIR"] = str(app.outdir) script = os.path.join(app.confdir, "sphinx-finished.sh") subprocess.check_call(script, shell=True) # # Hook the setup of readthedocs so we can hook into events as defined in: # - https://www.sphinx-doc.org/en/master/extdev/appapi.html # def setup(app): app.connect("build-finished", builder_finished_handler) tpm2-pytss-3.0.0-rc0/docs/constants.rst000066400000000000000000000002221506405471500177370ustar00rootroot00000000000000Constants ========= .. automodule:: tpm2_pytss.constants :members: :undoc-members: :inherited-members: int :special-members: __str__ tpm2-pytss-3.0.0-rc0/docs/contributing.rst000066400000000000000000000012211506405471500204320ustar00rootroot00000000000000Contributing ------------------- To contribute, please publish a PR and: - Keep within the existing style of black. The known working version is: ``~24.0``. - `Write a good commit message `_. - If possible prefix your commit with the affected subsystem and colon. For instance, if modifying docs do ``docs: my commit message``. - Run ``ruff check`` and fix any issues. - Agree to DCO (https://developercertificate.org/) by signing off your commit with git option ``-s`` or ``--sign-off``. - Optionally, sign your commit with ``-S`` or ``--gpg-sign``. - Write a test. tpm2-pytss-3.0.0-rc0/docs/cryptography.rst000066400000000000000000000001431506405471500204600ustar00rootroot00000000000000cryptography ============ .. automodule:: tpm2_pytss.cryptography :members: :undoc-members: tpm2-pytss-3.0.0-rc0/docs/esys.rst000066400000000000000000000001131506405471500167050ustar00rootroot00000000000000Esys ==== .. autoclass:: tpm2_pytss.ESAPI :members: :undoc-members: tpm2-pytss-3.0.0-rc0/docs/exception.rst000066400000000000000000000001501506405471500177210ustar00rootroot00000000000000TSS2_Exception ============== .. autoclass:: tpm2_pytss.TSS2_Exception :members: :undoc-members: tpm2-pytss-3.0.0-rc0/docs/fapi.rst000066400000000000000000000001121506405471500166400ustar00rootroot00000000000000FAPI ==== .. autoclass:: tpm2_pytss.FAPI :members: :undoc-members: tpm2-pytss-3.0.0-rc0/docs/index.rst000066400000000000000000000035741506405471500170470ustar00rootroot00000000000000tpm2-pytss Documentation ========================= This project provides a Python API to access the `tpm2-tss `_. If you're looking for how to connect to a TPM 2.0 device in Python, you're in the right place. The core libraries provide are: - tss2-esys: The Enhanced System API which is a simpler command interface to the TPM with full control and includes crypto protected session support: `See the ESAPI spec `_. - tss2-fapi: The Feature API is a high-level API to make interactions with the TPM as simple as possible and support automatic encrypted sessions when possible: `See the FAPI spec `_. - tss2-mu: The Marshaling and Unmarshaling API which provides serialization and deserialization of TPM data structures: `See the MU spec `_. - tss2-rc: The Response Code API, which provides a way to convert ``TSS2_RC`` error codes into human readable strings: `See the RC spec `_. - tss2-tctildr: The TPM Command Transmission Interface, which provides a way to get bytes to and from a TPM: `See the TCTI spec `_. Under the hood, bindings are provided via `CFFI `_. However, the Python API abstracts things quite a bit so you'll have to write less code. Supported versions of Python are: - 3.9 - 3.10 - 3.11 - 3.12 - 3.13 .. toctree:: :hidden: :maxdepth: 2 :caption: Contents: install API Testing Project Info GitHub tpm2-pytss-3.0.0-rc0/docs/install.rst000066400000000000000000000066341506405471500174060ustar00rootroot00000000000000Installing ========== Instructions for installing tpm2-pytss project. Quick Start ----------- - Install Dependencies: :ref:`Package Manager` - Install Python Package: :ref:`pip install` Install Dependencies -------------------- The python package will install the required python dependencies when you perform something like a `pip install`. However, one must satisfy the dependencies on the following native libraries that comprise the `tpm2-software `_ suite. .. note:: The **minimum supported version** of the **tpm2-tss** native library suite is **2.4.0**. The Core Libraries provided by the `tpm2-tss `_ project: Required Core Libraries: - tss2-esys - tss2-mu - tss2-rcdecode - tss2-tctildr Optional Core Libraries: - tss2-fapi Optional TCTIs: - tss2-tcti-device - tss2-tcti-swtpm - tss2-tcti-mssim - tss2-tcti-libtpms - tss2-tcti-pcap - tss2-tcti-cmd Optional TCTI's provided by `tpm2-abrmd `_ project: - tss2-tcti-abrmd .. note:: One needs at least one TCTI to satisfy a connection to a TPM 2.0 device. These libraries are available through the package manager for most contemporary versions of various Linux distros. It is important to note that you will need the dev versions. However, you can consult the various tpm2-software projects for help installing them from source https://github.com/tpm2-software. .. note:: That when you install from source, you may need to run :ref:`run ldconfig`. .. _Package Manager: Installing Dependencies using a Package Manager ----------------------------------------------- Example from Ubuntu 20.04 (No FAPI support): .. code-block:: bash apt-get update apt-get install libtss2-dev Example from Fedora 32: .. code-block:: bash dnf update dnf install tpm2-tss-devel .. _run ldconfig: ldconfig ~~~~~~~~ When you ran ``./configure`` for tpm2-tss if you didn't supply a prefix it usually defaults to ``/usr/local/``. When you ran ``make install`` it then installed the libraries under that path. Your package manager usually installs libraries to ``/usr``. If you properly configure the ``ldconfig`` tool, it'll make the libraries you just installed available from within ``/usr/local`` (which means they won't clash with things your package manager installs). If you don't configure it then you might get this error: .. code-block:: ImportError: libtss2-esys.so.0: cannot open shared object file: No such file or directory We make a config file that tells ``ldconfig`` to look in ``/usr/local/lib`` for shared libraries, then we run ``ldconfig``. .. code-block:: console $ sudo mkdir -p /etc/ld.so.conf.d/ $ echo 'include /etc/ld.so.conf.d/*.conf' | sudo tee -a /etc/ld.so.conf $ echo '/usr/local/lib' | sudo tee -a /etc/ld.so.conf.d/libc.conf $ sudo ldconfig .. note:: More info on ldconfig error: https://stackoverflow.com/a/17653893/3969496 .. _pip install: Install Using PyPi ------------------ Install from PyPi: .. code-block:: console $ python3 -m pip install tpm2-pytss .. note:: You may need to use option ``--user`` or elevated permissions, i.e. ``sudo`` to install site-wide depending on your particular environment. Or install from the Git repo: .. code-block:: console $ git clone --depth 1 https://github.com/tpm2-software/tpm2-pytss $ cd tpm2-pytss $ python3 -m pip install -e . tpm2-pytss-3.0.0-rc0/docs/maintainers.rst000066400000000000000000000005401506405471500202400ustar00rootroot00000000000000.. _maintainers: Project Maintainers ------------------- .. list-table:: Maintainers :header-rows: 1 * - Name - Email - GPG Key Id * - William Roberts - bill.c.roberts@gmail.com - D91A82DB310E8E07519C298A9877C26A3CD36409 * - Erik Larsson - who+github@cnackers.org - 2CAF442B36D6D5D0EB82FBEA28630DB7CEE35E6F tpm2-pytss-3.0.0-rc0/docs/policy.rst000066400000000000000000000001201506405471500172170ustar00rootroot00000000000000policy ====== .. autoclass:: tpm2_pytss.policy :members: :undoc-members: tpm2-pytss-3.0.0-rc0/docs/project.rst000066400000000000000000000005621506405471500174000ustar00rootroot00000000000000Project Information =================== Project details on release processes and contributing. .. toctree:: :maxdepth: 1 Release Process Contributing Maintainers Code of Conduct Security Practices LICENSE tpm2-pytss-3.0.0-rc0/docs/release.rst000066400000000000000000000102701506405471500173470ustar00rootroot00000000000000Release Process =============== Information on the release process and guidelines for maintainers. Milestones ----------- All releases should have a milestone used to track the release. If the release version is not known, as covered in `version string`_, 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`_ for details. Version Numbers --------------- Our releases will follow the semantic versioning scheme. You can find a thorough description of this scheme here: ``_ In short, this scheme has 3 parts to the version number: A.B.C - A is the 'major' version, incremented when an API incompatible change is made - B is the 'minor' version, incremented when an API compatible change is made - C is the 'micro' version, incremented for bug fix releases Please refer to the `Semantic Versioning `_ website for the authoritative description. .. _version string: Version String ^^^^^^^^^^^^^^ The version string is set by setup tools using `use_scm_version `_. Thus one must get a source built package from pypi or use the git repository. .. note:: The auto-generated zip and tarballs from GitHub WILL NOT WORK. 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: 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`_. The tag should be pushed to upstream git repo as the last step in the release process. Signed tags ^^^^^^^^^^^ Git supports GPG signed tags and for releases after the `1.1.0` release will have tags signed by a maintainer. For details on how to sign and verify git tags see ``_. Hosting Releases on PyPI ------------------------ The CI system has been automated to automatically create a release on any signed tag. This release will be packaged and uploaded to PyPi ``_. Hosting Documents on ReadTheDocs -------------------------------- For each tag, a ReadTheDocs (RTD) build must be conducted on LGTM manually after the release has been conducted. Maintainers should have access to the RTD page where they can select the reference and "activate" it in the release list. A fly-out menu contains the various versions and latest will point to master. See ``_ for more details. .. note:: Release Candidate Tags should be removed to prevent cluttering of the available document versioning. 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 ``_ Announcements ------------- Release candidates and proper releases should be announced on the 01.org TPM2 mailing list: ``_. 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. tpm2-pytss-3.0.0-rc0/docs/requirements.txt000066400000000000000000000003461506405471500204640ustar00rootroot00000000000000setuptools_scm[toml]>=3.4.3 cffi>=1.0.0 pkgconfig cryptography>=3.0 asn1crypto packaging pycparser cffi>=1.0.0 asn1crypto cryptography>=3.0 packaging pyyaml # needed for readthedocs builds: GitPython myst_parser sphinx_rtd_theme tpm2-pytss-3.0.0-rc0/docs/sphinx-finished.sh000077500000000000000000000012121506405471500206300ustar00rootroot00000000000000#!/usr/bin/env bash # SPDX-License-Identifier: BSD-2 # # This script is configured to run as part of the sphinx build # through API events registered in conf.py. # This script runs on event build-finished. # # This would be better served by handling the events # html-collect-page --> for add .nojekyll # html-page-context --> for fixing the span's done with sed. # # For the case of time, we just left this script as is and run it as a # post sphinx build command event :-p # set -eo pipefail find "${SPHINX_OUTDIR}" -name \*.html -exec \ sed -i 's/\>\>\> <\/span>//g' {} \; touch "${SPHINX_OUTDIR}"/.nojekyll exit 0 tpm2-pytss-3.0.0-rc0/docs/tcti.rst000066400000000000000000000003741506405471500166760ustar00rootroot00000000000000TCTI ==== .. automodule:: tpm2_pytss.TCTI :members: TCTI, PyTCTI :undoc-members: .. automodule:: tpm2_pytss.TCTILdr :members: TCTILdr :undoc-members: .. automodule:: tpm2_pytss.TCTISPIHelper :members: TCTISPIHelper :undoc-members: tpm2-pytss-3.0.0-rc0/docs/testing.rst000066400000000000000000000005741506405471500174120ustar00rootroot00000000000000Testing ------- You need to have ``tpm_server`` or ``swtpm`` installed in your path to run the tests. Download the latest version of tpm_server from https://sourceforge.net/projects/ibmswtpm2/files/ or swtpm from https://github.com/stefanberger/swtpm and put it somewhere in your ``$PATH``. .. code-block:: console $ pip install -e .[dev] $ pytest -n$(nproc) -v test tpm2-pytss-3.0.0-rc0/docs/tsskey.rst000066400000000000000000000001341506405471500172470ustar00rootroot00000000000000tsskey ====== .. automodule:: tpm2_pytss.tsskey :members: TSSPrivKey :undoc-members: tpm2-pytss-3.0.0-rc0/docs/types.rst000066400000000000000000000002051506405471500170700ustar00rootroot00000000000000Types ===== .. automodule:: tpm2_pytss.types :members: :undoc-members: :inherited-members: int :special-members: __str__tpm2-pytss-3.0.0-rc0/docs/utils.rst000066400000000000000000000001211506405471500170610ustar00rootroot00000000000000utils ======== .. automodule:: tpm2_pytss.utils :members: :undoc-members: tpm2-pytss-3.0.0-rc0/pyproject.toml000066400000000000000000000007761506405471500171730ustar00rootroot00000000000000[build-system] requires = ["setuptools>=44", "setuptools_scm[toml]>=3.4.3", "pycparser", "pkgconfig"] build-backend = "setuptools.build_meta" [tool.setuptools_scm] [tool.black] required-version = 24 exclude = ''' ( /( \.eggs # exclude a few common directories in the | \.git # root of the project | \.hg | \.mypy_cache | \.tox | \.venv | _build | buck-out | build | dist | esys_binding.py ) ) ''' [tool.ruff.lint] select = ["F401", "F541"] tpm2-pytss-3.0.0-rc0/scripts/000077500000000000000000000000001506405471500157345ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/scripts/docs.sh000077500000000000000000000001361506405471500172230ustar00rootroot00000000000000#!/usr/bin/env sh # SPDX-License-Identifier: BSD-2 set -e sphinx-build -W -b html docs pages tpm2-pytss-3.0.0-rc0/scripts/get_deps.py000077500000000000000000000010671506405471500201070ustar00rootroot00000000000000#!/usr/bin/env python3 import argparse import configparser def main(): parser = argparse.ArgumentParser( description="Dumps requred dependencies from a setup.cfg file" ) parser.add_argument("filename", nargs="?", default="setup.cfg") args = parser.parse_args() c = configparser.ConfigParser() c.read(args.filename) packages = c["options"]["setup_requires"].replace("\n", " ").strip() packages += " " + c["options"]["install_requires"].replace("\n", " ").strip() print(packages) if __name__ == "__main__": main() tpm2-pytss-3.0.0-rc0/scripts/libtss2_build.py000066400000000000000000000062461506405471500210570ustar00rootroot00000000000000from cffi import FFI ffibuilder = FFI() import os import pkgconfig import sys libraries = ["tss2-esys", "tss2-tctildr", "tss2-rc", "tss2-mu"] if not pkgconfig.installed("tss2-esys", ">=2.4.0"): raise RuntimeError("Require tss2-esapi to be installed and at least version 2.4.0") # Needs some missing marshal routines like Tss2_MU_TPMU_ENCRYPTED_SECRET_Marshal if not pkgconfig.installed("tss2-mu", ">=2.4.0"): raise RuntimeError("Require tss2-mu 2.4.0 or greater to be installed") if not pkgconfig.exists("tss2-tctildr"): raise RuntimeError("Require tss2-tctildr to be installed") if not pkgconfig.exists("tss2-rc"): raise RuntimeError("Require tss2-rc to be installed") # FAPI must be version 3.0.0 or greater to work, else strip it. build_fapi = pkgconfig.installed("tss2-fapi", ">=3.0.0") if build_fapi: libraries.append("tss2-fapi") build_policy = pkgconfig.exists("tss2-policy") if build_policy: libraries.append("tss2-policy") build_tcti_spi_helper = pkgconfig.exists("tss2-tcti-spi-helper") if build_tcti_spi_helper: libraries.append("tss2-tcti-spi-helper") # Set up the search path so we find prepare_header and other modules PATH = os.path.dirname(__file__) if len(os.path.dirname(__file__)) > 0 else os.getcwd() if not os.path.isabs(PATH): PATH = os.path.join(os.getcwd(), PATH) print("adding path: {}".format(PATH)) sys.path.insert(0, PATH) from prepare_headers import prepare os.environ["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "1" libs = " ".join(libraries) paths = pkgconfig.parse(libs) found_dir = None for hd in paths["include_dirs"]: full_path = os.path.join(hd, "tss2", "tss2_common.h") if os.path.isfile(full_path): found_dir = hd break if found_dir is None: sys.exit("Could not find esys headers in {}".format(paths["include_dirs"])) # strip tss2 prefix prepare( found_dir, "libesys.h", build_fapi=build_fapi, build_policy=build_policy, build_tcti_spi_helper=build_tcti_spi_helper, ) ffibuilder.cdef(open("libesys.h").read()) source = """ /* the C header of the library */ #include #include #include #include #include /* * Add the structure for the Python TCTI which is the TCTI structure and void * * for the pyobject representing the object instance. We add it here and to * prepare headers so CFFI knows about it (prepare_headers) and here so * C code knows about it. */ typedef struct PYTCTI_CONTEXT PYTCTI_CONTEXT; struct PYTCTI_CONTEXT { TSS2_TCTI_CONTEXT_COMMON_V2 common; void *thiz; }; """ if build_fapi: source += " #include \n" if build_policy: source += " #include \n" if build_tcti_spi_helper: source += " #include " # so it is often just the "#include". ffibuilder.set_source( "tpm2_pytss._libtpm2_pytss", source, libraries=paths["libraries"], library_dirs=paths["library_dirs"], include_dirs=paths["include_dirs"], ) # library name, for the linker if __name__ == "__main__": ffibuilder.compile(verbose=True, debug=True) tpm2-pytss-3.0.0-rc0/scripts/prepare_headers.py000066400000000000000000000307511506405471500214450ustar00rootroot00000000000000#!/usr/bin/python3 # SPDX-License-Identifier: BSD-2 import os import pkgconfig import pathlib import re import sys import textwrap def remove_common_guards(s): # Remove includes and guards s = re.sub(r"#ifndef.*", r"", s) s = re.sub(r"#if .*", r"", s) s = re.sub(r"#define .*_H_*?\n", r"", s) s = re.sub(r"#endif.*", r"", s) s = re.sub(r"#error.*", r"", s) s = re.sub(r'#ifdef __cplusplus\nextern "C" {', r"", s, flags=re.MULTILINE) s = re.sub(r"#ifdef __cplusplus\n}", r"", s, flags=re.MULTILINE) s = re.sub(r"#include.*", "", s) # Remove certain macros s = re.sub(r"#define TSS2_API_VERSION.*", r"", s) s = re.sub(r"#define TSS2_ABI_VERSION.*", r"", s) s = re.sub(r"#define TSS2_RC_LAYER\(level\).*", r"", s) s = re.sub(r"(#define.*)TSS2_RC_LAYER\(0xff\)", r"\g<1>0xff0000", s) # Remove comments s = re.sub(r"/\*.*?\*/", "", s, flags=re.MULTILINE) # Restructure #defines with ... s = re.sub(r"(#define [A-Za-z0-9_]+) +\(\(.*?\) \(.*?\)\)", r"\g<1>...", s) s = re.sub(r"(#define [A-Za-z0-9_]+) +\(\(\(.*?\) .*\)", r"\g<1>...", s) s = re.sub(r"(#define [A-Za-z0-9_]+) +\(\(.*?\).*?\) ", r"\g<1>...", s) s = re.sub( r"(#define [A-Za-z0-9_]+) .*\n.*?.*\)\)", r"\g<1>...", s, flags=re.MULTILINE ) s = re.sub(r"(#define +[A-Za-z0-9_]+) +\((-?\d+)\)", r"\g<1> \g<2>", s) s = re.sub(r"(#define [A-Za-z0-9_]+) .*", r"\g<1>...", s) # Restructure structs and untions with ... s = re.sub(r"\[.+?\]", r"[...]", s) return s def remove_poll_stuff(s, poll_handle_type): r = r"#if defined\(__linux__\).*(\n.*)+#endif\n#endif" s = re.sub(r, rf"typedef struct pollfd {poll_handle_type};", s) return s def remove_INTERNALBUILD(s): r = r"#if\s+defined\(INTERNALBUILD\)(?:(?!endif).)*#endif" s = re.sub(r, "", s, flags=re.MULTILINE | re.DOTALL) s = re.sub(r"DEPRECATED", r"", s) return re.sub(r"__attribute__\(\(deprecated\)\)", r"", s) def prepare_common(dirpath): s = pathlib.Path(dirpath, "tss2_common.h").read_text(encoding="utf-8") return remove_common_guards(s) def prepare_types(dirpath): s = pathlib.Path(dirpath, "tss2_tpm2_types.h").read_text(encoding="utf-8") # Remove false define (workaround) s = re.sub( r"#define TPM2_MAX_TAGGED_POLICIES.*\n.*TPMS_TAGGED_POLICY\)\)", r"", s, flags=re.MULTILINE, ) s = remove_INTERNALBUILD(s) s = re.sub( r"typedef struct TPMS_ALGORITHM_DESCRIPTION TPMS_ALGORITHM_DESCRIPTION ;", r"", s, ) s = re.sub( r"struct TPMS_ALGORITHM_DESCRIPTION {\n.*\n.*\n} ;", r"", s, flags=re.MULTILINE ) return remove_common_guards(s) def prepare_tcti(dirpath): s = pathlib.Path(dirpath, "tss2_tcti.h").read_text(encoding="utf-8") s = re.sub(r"#ifndef TSS2_API_VERSION.*\n.*\n#endif", r"", s, flags=re.MULTILINE) s = remove_poll_stuff(s, "TSS2_TCTI_POLL_HANDLE") s = re.sub(r"#define TSS2_TCTI_.*\n.*", r"", s, flags=re.MULTILINE) s = re.sub(r"^\s*#define Tss2_Tcti_(?:.*\\\r?\n)*.*$", r"", s, flags=re.MULTILINE) s += """ struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; """ # Add the callbacks for a TCTI s += """ extern "Python" TSS2_RC _tcti_transmit_wrapper ( TSS2_TCTI_CONTEXT *tctiContext, size_t size, uint8_t const *command); extern "Python" TSS2_RC _tcti_receive_wrapper ( TSS2_TCTI_CONTEXT *tctiContext, size_t *size, uint8_t *response, int32_t timeout); extern "Python" void _tcti_finalize_wrapper ( TSS2_TCTI_CONTEXT *tctiContext); extern "Python" TSS2_RC _tcti_cancel_wrapper ( TSS2_TCTI_CONTEXT *tctiContext); extern "Python" TSS2_RC _tcti_get_pollfds_wrapper ( TSS2_TCTI_CONTEXT *tctiContext, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); extern "Python" TSS2_RC _tcti_set_locality_wrapper ( TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); extern "Python" TSS2_RC _tcti_make_sticky_wrapper ( TSS2_TCTI_CONTEXT *tctiContext, TPM2_HANDLE *handle, uint8_t sticky); """ # Add this struct here so CFFI knows about it and its size s += """ typedef struct PYTCTI_CONTEXT PYTCTI_CONTEXT; struct PYTCTI_CONTEXT { TSS2_TCTI_CONTEXT_COMMON_V2 common; void *thiz; }; """ return remove_common_guards(s) def prepare_tcti_ldr(dirpath): s = pathlib.Path(dirpath, "tss2_tctildr.h").read_text(encoding="utf-8") return remove_common_guards(s) def prepare_tcti_spi_helper(dirpath): s = pathlib.Path(dirpath, "tss2_tcti_spi_helper.h").read_text(encoding="utf-8") # Add the callbacks for a TCTI s += """ extern "Python" TSS2_RC _tcti_spi_helper_sleep_ms ( void *userdata, int milliseconds); extern "Python" TSS2_RC _tcti_spi_helper_start_timeout ( void *userdata, int milliseconds); extern "Python" TSS2_RC _tcti_spi_helper_timeout_expired ( void *userdata, bool *is_timeout_expired); extern "Python" TSS2_RC _tcti_spi_helper_spi_acquire ( void *userdata); extern "Python" TSS2_RC _tcti_spi_helper_spi_release ( void *userdata); extern "Python" TSS2_RC _tcti_spi_helper_spi_transfer ( void *userdata, const void *data_out, void *data_in, size_t cnt); extern "Python" void _tcti_spi_helper_finalize ( void *userdata); """ return remove_common_guards(s) def prepare_sapi(): return "typedef struct TSS2_SYS_CONTEXT TSS2_SYS_CONTEXT;" def prepare_esapi(dirpath): s = pathlib.Path(dirpath, "tss2_esys.h").read_text(encoding="utf-8") return remove_common_guards(s) def prepare_fapi(dirpath): s = pathlib.Path(dirpath, "tss2_fapi.h").read_text(encoding="utf-8") s = remove_poll_stuff(s, "FAPI_POLL_HANDLE") s += """ extern "Python" TSS2_RC _fapi_auth_callback( char const *objectPath, char const *description, char const **auth, void *userData); extern "Python" TSS2_RC _fapi_branch_callback( char const *objectPath, char const *description, char const **branchNames, size_t numBranches, size_t *selectedBranch, void *userData); extern "Python" TSS2_RC _fapi_sign_callback( char const *objectPath, char const *description, char const *publicKey, char const *publicKeyHint, uint32_t hashAlg, uint8_t const *dataToSign, size_t dataToSignSize, uint8_t const **signature, size_t *signatureSize, void *userData); extern "Python" TSS2_RC _fapi_policy_action_callback( char const *objectPath, char const *action, void *userData); """ return remove_common_guards(s) def prepare_rcdecode(dirpath): s = pathlib.Path(dirpath, "tss2_rc.h").read_text(encoding="utf-8") return remove_common_guards(s) def prepare_mu(dirpath): s = pathlib.Path(dirpath, "tss2_mu.h").read_text(encoding="utf-8") s = remove_INTERNALBUILD(s) s = remove_common_guards(s) # At least tpm2-tss 3.0.3 have duplicated BYTE (un)marshal functions which break cffi # So removing them is needed until 3.1.x has reached most distributions n = re.findall( r"TSS2_RC\s+Tss2_MU_BYTE_Marshal\(.+?\);", s, re.DOTALL | re.MULTILINE ) if len(n) > 1: s = re.sub( r"TSS2_RC\s+Tss2_MU_BYTE_Marshal\(.+?\);", r"", s, 1, re.DOTALL | re.MULTILINE, ) n = re.findall( r"TSS2_RC\s+Tss2_MU_BYTE_Unmarshal\(.+?\);", s, re.DOTALL | re.MULTILINE ) if len(n) > 1: s = re.sub( r"TSS2_RC\s+Tss2_MU_BYTE_Unmarshal\(.+?\);", r"", s, 1, re.DOTALL | re.MULTILINE, ) s = re.sub( r"TSS2_RC\s+Tss2_MU_TPMS_ALGORITHM_DESCRIPTION_Marshal\(.+?\)\s+;", r"", s, 1, re.DOTALL | re.MULTILINE, ) s = re.sub( r"TSS2_RC\s+Tss2_MU_TPMS_ALGORITHM_DESCRIPTION_Unmarshal\(.+?\)\s+;", "", s, 1, re.DOTALL | re.MULTILINE, ) return s def prepare_policy(dirpath): s = pathlib.Path(dirpath, "tss2_policy.h").read_text(encoding="utf-8") s = remove_common_guards(s) # cparser complains if a typedef of an enum is before the definition of the enum s = re.sub( r"typedef enum TSS2_POLICY_PCR_SELECTOR TSS2_POLICY_PCR_SELECTOR;", r"", s, 1 ) s = re.sub( r"(enum TSS2_POLICY_PCR_SELECTOR.*?\};)", r"\1" + "\ntypedef enum TSS2_POLICY_PCR_SELECTOR TSS2_POLICY_PCR_SELECTOR;", s, 1, re.DOTALL | re.MULTILINE, ) s += """ extern "Python" TSS2_RC _policy_cb_calc_pcr( TSS2_POLICY_PCR_SELECTION *selection, TPML_PCR_SELECTION *out_selection, TPML_DIGEST *out_digest, void *userdata); extern "Python" TSS2_RC _policy_cb_calc_name( const char *path, TPM2B_NAME *name, void *userdata); extern "Python" TSS2_RC _policy_cb_calc_public( const char *path, TPMT_PUBLIC *public, void *userdata); extern "Python" TSS2_RC _policy_cb_calc_nvpublic( const char *path, TPMI_RH_NV_INDEX nv_index, TPMS_NV_PUBLIC *nv_public, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_auth( TPM2B_NAME *name, ESYS_TR *object_handle, ESYS_TR *auth_handle, ESYS_TR *authSession, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_polsel( TSS2_OBJECT *auth_object, const char **branch_names, size_t branch_count, size_t *branch_idx, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_sign( char *key_pem, char *public_key_hint, TPMI_ALG_HASH key_pem_hash_alg, uint8_t *buffer, size_t buffer_size, const uint8_t **signature, size_t *signature_size, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_polauth( TPMT_PUBLIC *key_public, TPMI_ALG_HASH hash_alg, TPM2B_DIGEST *digest, TPM2B_NONCE *policyRef, TPMT_SIGNATURE *signature, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_polauthnv( TPMS_NV_PUBLIC *nv_public, TPMI_ALG_HASH hash_alg, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_poldup( TPM2B_NAME *name, void *userdata); extern "Python" TSS2_RC _policy_cb_exec_polaction( const char *action, void *userdata); """ return s def prepare( indir, outfile, build_fapi=True, build_policy=True, build_tcti_spi_helper=True ): indir = os.path.join(indir, "tss2") common = prepare_common(indir) types = prepare_types(indir) tcti = prepare_tcti(indir) tcti_ldr = prepare_tcti_ldr(indir) if build_tcti_spi_helper: tcti_spi_helper = prepare_tcti_spi_helper(indir) sapi = prepare_sapi() esapi = prepare_esapi(indir) if build_fapi: fapi = prepare_fapi(indir) rcdecode = prepare_rcdecode(indir) mu = prepare_mu(indir) if build_policy: policy = prepare_policy(indir) # Write result with open(outfile, "w") as f: f.write( textwrap.dedent( """ /* * SPDX-License-Identifier: BSD-2 * This file was automatically generated. Do not modify ! */ """ ) ) f.write(common) f.write(types) f.write(tcti) f.write(tcti_ldr) if build_tcti_spi_helper: f.write(tcti_spi_helper) f.write(sapi) f.write(esapi) if build_fapi: f.write(fapi) f.write(rcdecode) f.write(mu) if build_policy: f.write(policy) if __name__ == "__main__": if len(sys.argv) != 3: print("Usage: {0} ".format(sys.argv[0])) exit(1) build_fapi = pkgconfig.installed("tss2-fapi", ">=3.0.0") build_tcti_spi_helper = pkgconfig.exists("tss2-tcti-spi-helper") prepare( sys.argv[1], sys.argv[2], build_fapi=build_fapi, build_tcti_spi_helper=build_tcti_spi_helper, ) tpm2-pytss-3.0.0-rc0/setup.cfg000066400000000000000000000023171506405471500160710ustar00rootroot00000000000000[metadata] name = tpm2-pytss author = William Roberts author_email = william.c.roberts@intel.com license = BSD description = TPM 2.0 TSS Bindings for Python url = https://github.com/tpm2-software/tpm2-pytss long_description = file: README.md long_description_content_type = text/markdown classifiers = Intended Audience :: Developers License :: OSI Approved :: BSD License Natural Language :: English Operating System :: OS Independent Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3.13 [options] package_dir= =src packages= tpm2_pytss tpm2_pytss.internal setup_requires = setuptools_scm[toml]>=3.4.3 cffi>=1.0.0 pkgconfig cryptography>=43.0.0 asn1crypto packaging pycparser install_requires = cffi>=1.0.0 asn1crypto cryptography>=43.0.0 packaging [options.extras_require] dev = docutils==0.16 coverage sphinx sphinx-rtd-theme twine setuptools_scm[toml]>=3.4.3 black~=24.0 pytest pytest-xdist pytest-cov myst-parser build installer ruff tpm2-pytss-3.0.0-rc0/setup.py000066400000000000000000000250101506405471500157550ustar00rootroot00000000000000import site import sys import os import platform from setuptools import setup from setuptools.command.build_ext import build_ext from pkgconfig import pkgconfig from pycparser import c_parser, preprocess_file from pycparser.c_ast import ( Typedef, TypeDecl, IdentifierType, Struct, ArrayDecl, Union, Enum, ) from textwrap import dedent # workaround bug https://github.com/pypa/pip/issues/7953 site.ENABLE_USER_SITE = "--user" in sys.argv[1:] def cpp_path(): return os.environ.get("CC", "cc") def cpp_args(args=[]): return ["-E"] + args class type_generator(build_ext): cares = set( ( "TPM2_ALG_ID", "TPM2_ST", "TPM2_ECC_CURVE", "TPM2_CC", "TPM2_CAP", "TPM2_PT", "TPM2_PT_PCR", "TPMA_SESSION", "TPMA_LOCALITY", "TPMA_NV", "TPMA_CC", "TPMA_OBJECT", "TPMA_ALGORITHM", "TPMA_ACT", "TPM2_HANDLE", "TPM2_GENERATED", "ESYS_TR", "TSS2_POLICY_PCR_SELECTOR", "TPM_AT", ) ) type_mapping = { "TPM2_ALG_ID": "TPM2_ALG", "TPMI_RH_HIERARCHY": "TPM2_RH", "TPMI_RH_ENABLES": "TPM2_RH", "TPMI_RH_HIERARCHY_AUTH": "TPM2_RH", "TPMI_RH_HIERARCHY_POLICY": "TPM2_RH", "TPMI_RH_PLATFORM": "TPM2_RH", "TPMI_RH_OWNER": "TPM2_RH", "TPMI_RH_ENDORSEMENT": "TPM2_RH", "TPMI_RH_PROVISION": "TPM2_RH", "TPMI_RH_CLEAR": "TPM2_RH", "TPMI_RH_NV_AUTH": "TPM2_RH", "TPMI_RH_LOCKOUT": "TPM2_RH", "TPMI_RH_NV_INDEX": "TPM2_RH", "TPMI_RH_AC": "TPM2_RH", "TPMI_RH_ACT": "TPM2_RH", } map_template = """ # SPDX-License-Identifier: BSD-2 # this file is autogenerated during the build _type_map = {{ {mstr} }} _element_type_map = {{ {estr} }} """ version_template = """ # SPDX-License-Identifier: BSD-2 # this file is autogenerated during the build _versions = {{ {vstr} }} """ version_libs = ("tss2-esys", "tss2-fapi", "tss2-policy", "tss2-tcti-spi-helper") def get_types(self, ast): tm = dict() for v in ast: if ( isinstance(v, Typedef) and isinstance(v.type, TypeDecl) and isinstance(v.type.type, (IdentifierType, Enum)) ): if hasattr(v.type.type, "names"): names = v.type.type.names elif hasattr(v.type.type, "name"): names = [v.type.type.name] name = " ".join(names) if v.name in self.type_mapping: tm[v.name] = self.type_mapping[v.name] elif name in self.type_mapping: tm[v.name] = self.type_mapping[name] elif name in self.cares: self.cares.add(v.name) tm[v.name] = name elif v.name in self.cares: tm[v.name] = v.name return tm def get_fields(self, v, tm): fields = list() nf = 0 for d in v.decls: nf = nf + 1 if not isinstance(d.type.type, (IdentifierType, Enum)): continue dn = d.name if hasattr(d.type.type, "names"): names = d.type.type.names elif hasattr(d.type.type, "name"): names = [d.type.type.name] tname = " ".join(names) if tname not in tm: continue fields.append((dn, tm[tname])) return fields def get_array_fields(self, v, tm): fields = list() nf = 0 for d in v.decls: nf = nf + 1 if not isinstance(d.type, ArrayDecl): continue tname = " ".join(d.type.type.type.names) if tname not in tm: continue fields.append(tm[tname]) return fields def get_first_struct(self, v): if isinstance(v, (Struct, Union)): return v while hasattr(v, "type"): v = v.type if isinstance(v, (Struct, Union)): return v return None def generate_mappings(self, ast, tm): mapping = dict() element_mapping = dict() for v in ast: if isinstance(v, Typedef): name = v.name v = self.get_first_struct(v) if v is None or getattr(v, "decls") is None: continue fields = self.get_fields(v, tm) for f in fields: mapping[(name, f[0])] = f[1] afields = self.get_array_fields(v, tm) for af in afields: element_mapping[name] = af return (mapping, element_mapping) def get_mappings(self): pk = pkgconfig.parse("tss2-esys") header_path = None for ip in pk["include_dirs"]: hp = os.path.join(ip, "tss2_tpm2_types.h") if os.path.isfile(hp): header_path = hp break hp = os.path.join(ip, "tss2", "tss2_tpm2_types.h") if os.path.isfile(hp): header_path = hp break if header_path is None: raise RuntimeError( f"unable to find tss2_tpm2_types.h in {pk['include_dirs']}" ) if platform.system() == "FreeBSD": pdata = preprocess_file( header_path, cpp_path=cpp_path(), cpp_args=cpp_args( [ "-std=c99", "-D__builtin_va_list=char*", "-D__extension__=", "-D__attribute__(x)=", ] ), ) else: pdata = preprocess_file( header_path, cpp_path=cpp_path(), cpp_args=cpp_args( ["-std=c99", "-D__extension__=", "-D__attribute__(x)="] ), ) parser = c_parser.CParser() ast = parser.parse(pdata, "tss2_tpm2_types.h") tm = self.get_types(ast) (mapping, element_mapping) = self.generate_mappings(ast, tm) if pkgconfig.exists("tss2-policy"): pk = pkgconfig.parse("tss2-policy") for ip in pk["include_dirs"]: hp = os.path.join(ip, "tss2_policy.h") if os.path.isfile(hp): policy_header_path = hp break hp = os.path.join(ip, "tss2", "tss2_policy") if os.path.isfile(hp): policy_header_path = hp break if policy_header_path: if platform.system() == "FreeBSD": pdata = preprocess_file( policy_header_path, cpp_path=cpp_path(), cpp_args=[ "-std=c99", "-D__builtin_va_list=char*", "-D__extension__=", "-D__attribute__(x)=", "-D__float128=long double", "-D_FORTIFY_SOURCE=0", ], ) else: pdata = preprocess_file( policy_header_path, cpp_path=cpp_path(), cpp_args=cpp_args( [ "-std=c99", "-D__extension__=", "-D__attribute__(x)=", "-D__float128=long double", "-D_FORTIFY_SOURCE=0", ] ), ) parser = c_parser.CParser() past = parser.parse(pdata, "tss2_policy.h") ptm = self.get_types(past) tm.update(ptm) (pmapping, pelement_mapping) = self.generate_mappings(past, ptm) mapping.update(pmapping) element_mapping.update(pelement_mapping) return (mapping, element_mapping) def get_versions(self): versions = dict() for lib in self.version_libs: try: versions[lib] = pkgconfig.modversion(lib) except pkgconfig.PackageNotFoundError: # Library not installed, ignore pass return versions def run(self): super().run() type_map, element_type_map = self.get_mappings() mstr = "" for k, v in type_map.items(): (t, f) = k mstr = mstr + f' ("{t}", "{f}"): "{v}",\n' mstr = mstr.rstrip() estr = "" for k, v in element_type_map.items(): estr = estr + f' "{k}": "{v}",\n' estr = estr.rstrip() versions = self.get_versions() vstr = "" for k, v in versions.items(): vstr = vstr + f' "{k}": "{v}",\n' vstr = vstr.rstrip() p = os.path.join(self.build_lib, "tpm2_pytss/internal/type_mapping.py") sp = os.path.join( os.path.dirname(__file__), "src/tpm2_pytss/internal/type_mapping.py" ) vp = os.path.join(self.build_lib, "tpm2_pytss/internal/versions.py") svp = os.path.join( os.path.dirname(__file__), "src/tpm2_pytss/internal/versions.py" ) print(f"generated _type_map with {len(type_map)} mappings in {p} and {sp}") print(f"generated _element_type_map with {len(element_type_map)} mappings") print(f"generated _versions with {len(versions)} versions") stempl = dedent(self.map_template) mout = stempl.format(mstr=mstr, estr=estr).lstrip() vtempl = dedent(self.version_template) vout = vtempl.format(vstr=vstr).lstrip() if not self.dry_run: self.mkpath(os.path.dirname(p)) with open(p, "wt") as tf: tf.seek(0) tf.truncate(0) tf.write(mout) with open(vp, "wt") as vf: vf.seek(0) vf.truncate(0) vf.write(vout) if self.inplace: self.copy_file(p, sp) self.copy_file(vp, svp) setup( use_scm_version=True, cffi_modules=["scripts/libtss2_build.py:ffibuilder"], cmdclass={"build_ext": type_generator}, ) tpm2-pytss-3.0.0-rc0/src/000077500000000000000000000000001506405471500150345ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/000077500000000000000000000000001506405471500171605ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/ESAPI.py000066400000000000000000010772771506405471500204200ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .types import * from .constants import * from .internal.utils import ( _chkrc, _get_dptr, _check_friendly_int, _fixup_classname, _lib_version_atleast, ) from .TCTI import TCTI from .TCTILdr import TCTILdr from typing import List, Optional, Tuple, Union # Work around this FAPI dependency if FAPI is not present with the constant value _fapi_installed_ = _lib_version_atleast("tss2-fapi", "3.0.0") _DEFAULT_LOAD_BLOB_SELECTOR = FAPI_ESYSBLOB.CONTEXTLOAD if _fapi_installed_ else 1 def _get_cdata(value, expected, varname, allow_none=False, *args, **kwargs): tname = expected.__name__ if value is None and allow_none: return ffi.NULL elif value is None: raise TypeError(f"expected {varname} to be {tname}, got None") if isinstance(value, ffi.CData): tipe = ffi.typeof(value) if tipe.kind == "pointer": tipe = tipe.item classname = _fixup_classname(tipe) if classname != tname: raise TypeError(f"expected {varname} to be {tname}, got {tipe.cname}") return value vname = type(value).__name__ parse_method = getattr(expected, "parse", None) if isinstance(value, (bytes, str)) and issubclass(expected, TPM2B_SIMPLE_OBJECT): bo = expected(value) return bo._cdata elif isinstance(value, str) and parse_method and callable(parse_method): return expected.parse(value, *args, **kwargs)._cdata elif issubclass(expected, TPML_OBJECT) and isinstance(value, list): return expected(value)._cdata elif not isinstance(value, expected): raise TypeError(f"expected {varname} to be {tname}, got {vname}") return value._cdata def _check_handle_type(handle, varname, expected=None): if not isinstance(handle, ESYS_TR): raise TypeError(f"expected {varname} to be type ESYS_TR, got {type(handle)}") if expected is not None and handle not in expected: if len(expected) > 1: msg = f"expected {varname} to be one of {','.join([ESYS_TR.to_string(x) for x in expected])}, got {ESYS_TR.to_string(handle)}" else: msg = f"expected {varname} to be {ESYS_TR.to_string(expected[0])}, got {ESYS_TR.to_string(handle)}" raise ValueError(msg) class ESAPI: """Initialize an ESAPI object for further use. Initialize an ESAPI object that holds all the state and metadata information during an interaction with the TPM. If tcti is None (the default), load a TCTI in this order: - Library libtss2-tcti-default.so (link to the preferred TCTI) - Library libtss2-tcti-tabrmd.so (tabrmd) - Device /dev/tpmrm0 (kernel resident resource manager) - Device /dev/tpm0 (hardware TPM) - TCP socket localhost:2321 (TPM simulator) Args: tcti (Union[TCTI, str]): The TCTI context used to connect to the TPM (may be None). This is established using TCTILdr or a tpm2-tools style --tcti string in the format of : where : is optional. Defaults to None. Returns: An instance of the ESAPI class. Raises: TypeError: If the TCTI is an invalid type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. RuntimeError: If a TCTI config string is not in name:conf or name format. This class implements the TCG defined Enhanced System API in Python see Notes below. Note that since this implementation is a binding, the underlying tss2-esys version will matter as far as the users mileage. Note that since the TCG has no specification on the ESAPI Python interface, liberties were taken to make use of features in Python not found in C. While the API is very similar to the C API, its not an exact match and, hopefully, will be simpler to use. The specification for the C library can be found at: - https://trustedcomputinggroup.org/resource/tcg-tss-2-0-enhanced-system-api-esapi-specification/ C Function: Esys_Initialize """ def __init__(self, tcti: Union[TCTI, str, None] = None): if not isinstance(tcti, (TCTI, type(None), str)): raise TypeError( f"Expected tcti to be type TCTI, str or None, got {type(tcti)}" ) self._did_load_tcti = False # support tpm2-tools style tcti strings if isinstance(tcti, str): self._did_load_tcti = True tcti = TCTILdr.parse(tcti) self._tcti: Optional[TCTI] = tcti tctx = ffi.NULL if tcti is None else tcti._tcti_context self._ctx_pp = ffi.new("ESYS_CONTEXT **") _chkrc(lib.Esys_Initialize(self._ctx_pp, tctx, ffi.NULL)) self._ctx = self._ctx_pp[0] def __enter__(self): return self def __exit__(self, _type, value, traceback) -> None: self.close() # # Close is used over tying this to the memory life cycle as __del__ means the GC has control # over when the underlying TCTI is free'd. Which could cause blocking from other ESAPI contexts # to the TPM. # def close(self) -> None: """Finalize an ESAPI Instance After interactions with the TPM the context holding the metadata needs to be freed. Since additional internal memory allocations may have happened during use of the context, it needs to be finalized correctly. C Function: Esys_Finalize """ if self._ctx_pp: lib.Esys_Finalize(self._ctx_pp) self._ctx = ffi.NULL self._ctx_pp = ffi.NULL if self._did_load_tcti and self._tcti is not None: self._tcti.close() self._tcti = None def is_closed(self) -> bool: """Checks if the ESAPI context is finalized. Returns: True is the ESAPI context is finalized else False. """ return not self._ctx_pp def get_tcti(self) -> Optional[TCTI]: """Return the used TCTI context. If a TCTI was passed into Esys_Initialize then this tcti context is return. If None was passed in, then None will be returned. This function is useful before Esys_Finalize to retrieve the tcti context and perform a clean Tss2_Tcti_Finalize. Returns: A TCTI or None if None was passed to the ESAPI constructor. """ return self._tcti @property def tcti(self) -> Optional[TCTI]: """Same as get_tcti()""" return self.get_tcti() def tr_from_tpmpublic( self, handle: TPM2_HANDLE, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Creation of an ESYS_TR object from TPM metadata. This function can be used to create ESYS_TR object for Tpm Resources that are not created or loaded (e.g. using ESys_CreatePrimary or ESys_Load) but pre-exist inside the TPM. Examples are NV-Indices or persistent object. Since man in the middle attacks should be prevented as much as possible it is recommended to pass a session. Note: For PCRs and hierarchies, please use the global ESYS_TR identifiers. Note: If a session is provided the TPM is queried for the metadata twice. First without a session to retrieve some metadata then with the session where this metadata is used in the session HMAC calculation and thereby verified. Args: handle (TPM2_HANDLE): The handle of the TPM object to represent as ESYS_TR. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Returns: The newly created ESYS_TR metadata object. Raises: TypeError: If a type is not expected. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TR_FromTPMPublic """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") obj = ffi.new("ESYS_TR *") _chkrc( lib.Esys_TR_FromTPMPublic( self._ctx, handle, session1, session2, session3, obj ) ) return ESYS_TR(obj[0]) def tr_close(self, esys_handle: ESYS_TR) -> None: """Close an ESYS_TR without removing it from the TPM. This function deletes an ESYS_TR object from an ESYS_CONTEXT without deleting it from the TPM. This is useful for NV-Indices or persistent keys, after ESAPI.tr_serialize has been called. Transient objects should be deleted using ESAPI.flush_context. Args: esys_handle (ESYS_TR): The ESYS_TR metadata object to be deleted from ESAPI. Raises: TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TR_Close """ _check_handle_type(esys_handle, "esys_handle") esys_tr_ptr = ffi.new("ESYS_TR *") esys_tr_ptr[0] = esys_handle _chkrc(lib.Esys_TR_Close(self._ctx, esys_tr_ptr)) def tr_set_auth( self, esys_handle: ESYS_TR, auth_value: Union[TPM2B_AUTH, bytes, str, None] ) -> None: """Set the authorization value of an ESYS_TR. Authorization values are associated with ESYS_TR Tpm Resource object. They are then picked up whenever an authorization is needed. Note: The authorization value is not stored in the metadata during tr_serialize. Therefore tr_set_auth needs to be called again after every tr_deserialize. Args: esys_handle (ESYS_TR): The ESYS_TR for which to set the auth_value value. auth_value (Union[TPM2B_AUTH, bytes, str, None]): The auth_value value to set for the ESYS_TR or None to zero. Defaults to None. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TR_SetAuth """ _check_handle_type(esys_handle, "esys_handle") if auth_value is None: auth_value = TPM2B_AUTH() auth_cdata = _get_cdata(auth_value, TPM2B_AUTH, "auth_value") _chkrc(lib.Esys_TR_SetAuth(self._ctx, esys_handle, auth_cdata)) def tr_get_name(self, handle: ESYS_TR) -> TPM2B_NAME: """Retrieve the TPM public name of an Esys_TR object. Some operations (i.e. Esys_PolicyNameHash) require the name of a TPM object to be passed. Esys_TR_GetName provides this name to the caller. Args: handle (ESYS_TR): The ESYS_TR for which to get the name value. Returns: A TPM2B_NAME containing the name of the object referenced in the esys_handle. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TR_GetName """ _check_handle_type(handle, "handle") name = ffi.new("TPM2B_NAME **") _chkrc(lib.Esys_TR_GetName(self._ctx, handle, name)) return TPM2B_NAME(_cdata=_get_dptr(name, lib.Esys_Free)) def startup(self, startup_type: TPM2_SU) -> None: """Invoke the TPM2_Startup command. This function invokes the TPM2_Startup command in a one-call variant. This means the function will block until the TPM response is available. Args: startup_type (TPM2_SU): TPM2_SU_CLEAR or TPM2_SU_STATE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_Startup TPM Command: TPM2_Startup """ _check_friendly_int(startup_type, "startup_type", TPM2_SU) _chkrc(lib.Esys_Startup(self._ctx, startup_type)) def shutdown( self, shutdown_type: TPM2_SU = TPM2_SU.STATE, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_Shutdown command. This function invokes the TPM2_Shutdown command in a one-call variant. This means the function will block until the TPM response is available. Args: shutdown_type (TPM2_SU): TPM2_SU_CLEAR or TPM2_SU_STATE. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_Shutdown TPM Command: TPM2_Shutdown """ _check_friendly_int(shutdown_type, "shutdown_type", TPM2_SU) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_Shutdown(self._ctx, session1, session2, session3, shutdown_type) ) def self_test( self, full_test: bool, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_SelfTest command. This function invokes the TPM2_SelfTest command in a one-call variant. This means the function will block until the TPM response is available. Args: full_test (bool): True to run a full test. False to run tests that have yet to be executed. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_SelfTest TPM Command: TPM2_SelfTest """ if not isinstance(full_test, bool): raise TypeError( f"Expected full_test to be type bool, got {type(full_test)}" ) _chkrc(lib.Esys_SelfTest(self._ctx, session1, session2, session3, full_test)) def incremental_self_test( self, to_test: TPML_ALG, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPML_ALG: """Invoke the TPM2_IncrementalSelfTest command. This function invokes the TPM2_IncrementalSelfTest command in a one-call variant. This means the function will block until the TPM response is available. Args: to_test (TPML_ALG): List of algorithms that should be tested. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPML_ALG list of of algorithms that need testing; the todo list. C Function: Esys_IncrementalSelfTest TPM Command: TPM2_IncrementalSelfTest """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") to_test_cdata = _get_cdata(to_test, TPML_ALG, "to_test") todo_list = ffi.new("TPML_ALG **") _chkrc( lib.Esys_IncrementalSelfTest( self._ctx, session1, session2, session3, to_test_cdata, todo_list ) ) return TPML_ALG(_get_dptr(todo_list, lib.Esys_Free)) def get_test_result( self, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_MAX_BUFFER, TPM2_RC]: """Invoke the TPM2_GetTestResult command. This function invokes the TPM2_GetTestResult command in a one-call variant. This means the function will block until the TPM response is available. Args: session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_MAX_BUFFER, TPM2_RC] the test result data and the return code from the test execution. C Function: Esys_GetTestResult TPM Command: TPM2_GetTestResult """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") out_data = ffi.new("TPM2B_MAX_BUFFER **") test_result = ffi.new("TPM2_RC *") _chkrc( lib.Esys_GetTestResult( self._ctx, session1, session2, session3, out_data, test_result ) ) return ( TPM2B_MAX_BUFFER(_get_dptr(out_data, lib.Esys_Free)), TPM2_RC(test_result[0]), ) def start_auth_session( self, tpm_key: ESYS_TR, bind: ESYS_TR, session_type: TPM2_SE, symmetric: Union[TPMT_SYM_DEF, str, None], auth_hash: TPM2_ALG, nonce_caller: Union[TPM2B_NONCE, bytes, str, None] = None, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_StartAuthSession command. This function invokes the TPM2_StartAuthSession command in a one-call variant. This means the function will block until the TPM response is available. Args: tpm_key (ESYS_TR): Handle of a loaded decrypt key used to encrypt salt. bind (ESYS_TR): Entity providing the authValue. session_type (TPM2_SE): Indicates the type of the session; simple HMAC or policy (including a trial policy). symmetric (TPMT_SYM_DEF, str, None): The algorithm and key size for parameter encryption. Can use strings understood by TPMT_SYM_DEF.parse() and None set the algorithm to TPM2_ALG.NULL. auth_hash (TPM2_ALG, str): Hash algorithm to use for the session. Can use strings as understood by TPM2_ALG.parse(). nonce_caller (Union[TPM2B_NONCE, bytes, str, None]): Initial nonceCaller, sets nonceTPM size for the session. Can be None to have ESAPI generate it for the caller. Defaults to None. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR which is the handle of the started session. C Function: Esys_StartAuthSession TPM Command: TPM2_StartAuthSession """ _check_handle_type(tpm_key, "tpm_key") _check_handle_type(bind, "bind") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(session_type, "session_type", TPM2_SE) if isinstance(auth_hash, str): auth_hash = TPM2_ALG.parse(auth_hash) _check_friendly_int(auth_hash, "auth_hash", TPM2_ALG) nonce_caller_cdata = _get_cdata( nonce_caller, TPM2B_NONCE, "nonce_caller", allow_none=True ) if isinstance(symmetric, str): symmetric = TPMT_SYM_DEF.parse(symmetric) elif symmetric is None: symmetric = TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL) symmetric_cdata = _get_cdata(symmetric, TPMT_SYM_DEF, "symmetric") session_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_StartAuthSession( self._ctx, tpm_key, bind, session1, session2, session3, nonce_caller_cdata, session_type, symmetric_cdata, auth_hash, session_handle, ) ) return ESYS_TR(session_handle[0], ectx=self) def trsess_set_attributes( self, session: ESYS_TR, attributes: Union[TPMA_SESSION, int], mask: int = 0xFF ) -> None: """Set session attributes. Set or unset a session's attributes according to the provided flags and mask. ``new_attributes = old_attributes & ~mask | flags & mask`` Note: this function only applies to ESYS_TR objects that represent sessions. Args: session (ESYS_TR): The session handle. attributes (Union[TPMA_SESSION, int]): The attributes to be set or unset for the session. mask (int): The mask for the flags to be set or unset. Defaults to 0xFF. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TRSess_SetAttributes """ _check_handle_type(session, "session") if not isinstance(attributes, (TPMA_SESSION, int)): raise TypeError( f"Expected attributes to be type int, got {type(attributes)}" ) if not isinstance(mask, int): raise TypeError(f"Expected mask to be type int, got {type(attributes)}") _chkrc(lib.Esys_TRSess_SetAttributes(self._ctx, session, attributes, mask)) def trsess_get_attributes(self, session: ESYS_TR) -> TPMA_SESSION: """Get session attributes. Get the session attributes. Note: this function only applies to ESYS_TR objects that represent sessions. Args: session (ESYS_TR): The session handle. Returns: The TPMA_SESSION attributes for the session Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TRSess_GetAttributes """ _check_handle_type(session, "session") attributes = ffi.new("TPMA_SESSION *") _chkrc(lib.Esys_TRSess_GetAttributes(self._ctx, session, attributes)) return TPMA_SESSION(attributes[0]) def trsess_get_nonce_tpm(self, session: ESYS_TR) -> TPM2B_NONCE: """Retrieve the TPM nonce of an Esys_TR session object. Some operations (i.e. Esys_PolicySigned) require the nonce returned by the TPM during Esys_StartauthSession. This function provides this nonce to the caller. Args: session (ESYS_TR): The session handle. Returns: The TPMB_NONCE representing the current session nonce. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TRSess_GetNonceTPM """ _check_handle_type(session, "session") nonce = ffi.new("TPM2B_NONCE **") _chkrc(lib.Esys_TRSess_GetNonceTPM(self._ctx, session, nonce)) return TPM2B_NONCE(_get_dptr(nonce, lib.Esys_Free)) def tr_get_tpm_handle(self, esys_handle: ESYS_TR) -> TPM2_HANDLE: """Retrieves the associated TPM2_HANDLE from an ESYS_TR object. Retrieves the TPM2_HANDLE for an associated ESYS_TR object for use with the SAPI API or comparisons against raw TPM2_HANDLES from commands like TPM2_GetCapability or use of various handle bitwise comparisons. For example the mask TPM2_HR_NV_INDEX. Args: esys_handle (ESYS_TR): The ESYS_TR object to retrieve the TPM2_HANDLE from. Returns: The TPM2_HANDLE retrieved from the ESYS_TR object. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TR_GetTpmHandle """ _check_handle_type(esys_handle, "esys_handle") tpm_handle = ffi.new("ESYS_TR *") _chkrc(lib.Esys_TR_GetTpmHandle(self._ctx, esys_handle, tpm_handle)) return TPM2_HANDLE(tpm_handle[0]) def policy_restart( self, session_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyRestart command. This function invokes the TPM2_PolicyRestart command in a one-call variant. This means the function will block until the TPM response is available. Args: session_handle (ESYS_TR): The handle for the policy session. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyRestart TPM Command: TPM2_PolicyRestart """ _check_handle_type(session_handle, "session_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyRestart( self._ctx, session_handle, session1, session2, session3 ) ) def create( self, parent_handle: ESYS_TR, in_sensitive: Optional[TPM2B_SENSITIVE_CREATE], in_public: Union[TPM2B_PUBLIC, str] = "rsa2048", outside_info: Union[TPM2B_DATA, bytes, str] = TPM2B_DATA(), creation_pcr: Union[TPML_PCR_SELECTION, str] = TPML_PCR_SELECTION(), session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[ TPM2B_PRIVATE, TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION ]: """Invoke the TPM2_Create command. This function invokes the TPM2_Create command in a one-call variant. This means the function will block until the TPM response is available. Args: parent_handle (ESYS_TR): Handle of parent for new object. in_sensitive (TPM2B_SENSITIVE_CREATE): The sensitive data, can be None for an empty TPM2B_SENSITIVE_CREATE. in_public (Union[TPM2B_PUBLIC, str]): The public template. Defaults to an rsa2048 template. outside_info (Union[TPM2B_DATA, bytes, str]): Data that will be included in the creation data for this object to provide permanent, verifiable linkage between this object and some object owner data. Defaults to empty TPM2B_DATA. creation_pcr (Union[TPML_PCR_SELECTION, str]): PCR that will be used in creation data. Defaults to an empty PCR selection. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An Tuple[TPM2B_PRIVATE, TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION]. C Function: Esys_Create TPM Command: TPM2_Create """ _check_handle_type(parent_handle, "parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_public_cdata = _get_cdata(in_public, TPM2B_PUBLIC, "in_public") if in_sensitive is None: in_sensitive = TPM2B_SENSITIVE_CREATE() in_sensitive_cdata = _get_cdata( in_sensitive, TPM2B_SENSITIVE_CREATE, "in_sensitive" ) outside_info_cdata = _get_cdata(outside_info, TPM2B_DATA, "outside_info") creation_pCR_cdata = _get_cdata( creation_pcr, TPML_PCR_SELECTION, "creation_pcr" ) out_private = ffi.new("TPM2B_PRIVATE **") out_public = ffi.new("TPM2B_PUBLIC **") creation_data = ffi.new("TPM2B_CREATION_DATA **") creation_hash = ffi.new("TPM2B_DIGEST **") creation_ticket = ffi.new("TPMT_TK_CREATION **") _chkrc( lib.Esys_Create( self._ctx, parent_handle, session1, session2, session3, in_sensitive_cdata, in_public_cdata, outside_info_cdata, creation_pCR_cdata, out_private, out_public, creation_data, creation_hash, creation_ticket, ) ) return ( TPM2B_PRIVATE(_get_dptr(out_private, lib.Esys_Free)), TPM2B_PUBLIC(_get_dptr(out_public, lib.Esys_Free)), TPM2B_CREATION_DATA(_get_dptr(creation_data, lib.Esys_Free)), TPM2B_DIGEST(_get_dptr(creation_hash, lib.Esys_Free)), TPMT_TK_CREATION(_get_dptr(creation_ticket, lib.Esys_Free)), ) def load( self, parent_handle: ESYS_TR, in_private: TPM2B_PRIVATE, in_public: TPM2B_PUBLIC, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_Load command. This function invokes the TPM2_Load command in a one-call variant. This means the function will block until the TPM response is available. Args: parent_handle (ESYS_TR): parentHandle TPM handle of parent key; shall not be a reserved handle. in_private (TPM2B_PRIVATE): The private portion of the object. in_public (TPM2B_PUBLIC): The public portion of the object. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR representing the handle of the loaded object. C Function: Esys_Load TPM Command: TPM2_Load """ _check_handle_type(parent_handle, "parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_public_cdata = _get_cdata(in_public, TPM2B_PUBLIC, "in_public") in_private_cdata = _get_cdata(in_private, TPM2B_PRIVATE, "in_private") object_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_Load( self._ctx, parent_handle, session1, session2, session3, in_private_cdata, in_public_cdata, object_handle, ) ) return ESYS_TR(object_handle[0], ectx=self) def load_external( self, in_public: TPM2B_PUBLIC, in_private: TPM2B_SENSITIVE = None, hierarchy: ESYS_TR = ESYS_TR.NULL, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_LoadExternal command. This function invokes the TPM2_LoadExternal command in a one-call variant. This means the function will block until the TPM response is available. Args: in_public (TPM2B_PUBLIC): The public portion of the object. in_private (TPM2B_SENSITIVE): The sensitive portion of the object. Defaults to None. hierarchy (ESYS_TR): Hierarchy with which the object area is associated. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR representing the handle of the loaded object. C Function: Esys_LoadExternal TPM Command: TPM2_LoadExternal """ _check_friendly_int(hierarchy, "hierarchy", ESYS_TR) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_private_cdata = _get_cdata( in_private, TPM2B_SENSITIVE, "in_private", allow_none=True ) in_public_cdata = _get_cdata(in_public, TPM2B_PUBLIC, "in_public") hierarchy = ESAPI._fixup_hierarchy(hierarchy) object_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_LoadExternal( self._ctx, session1, session2, session3, in_private_cdata, in_public_cdata, hierarchy, object_handle, ) ) return ESYS_TR(object_handle[0], ectx=self) def read_public( self, object_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_PUBLIC, TPM2B_NAME, TPM2B_NAME]: """Invoke the TPM2_ReadPublic command. This function invokes the TPM2_ReadPublic command in a one-call variant. This means the function will block until the TPM response is available. Args: object_handle (ESYS_TR): Handle of the object. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_PUBLIC, TPM2B_NAME, TPM2B_NAME] which is the public portion of the object, the name and the qualified name respectively. C Function: Esys_ReadPublic TPM Command: TPM2_ReadPublic """ _check_handle_type(object_handle, "object_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") out_public = ffi.new("TPM2B_PUBLIC **") name = ffi.new("TPM2B_NAME **") qualified_name = ffi.new("TPM2B_NAME **") _chkrc( lib.Esys_ReadPublic( self._ctx, object_handle, session1, session2, session3, out_public, name, qualified_name, ) ) return ( TPM2B_PUBLIC(_get_dptr(out_public, lib.Esys_Free)), TPM2B_NAME(_get_dptr(name, lib.Esys_Free)), TPM2B_NAME(_get_dptr(qualified_name, lib.Esys_Free)), ) def activate_credential( self, activate_handle: ESYS_TR, key_handle: ESYS_TR, credential_blob: TPM2B_ID_OBJECT, secret: TPM2B_ENCRYPTED_SECRET, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DIGEST: """Invoke the TPM2_ActivateCredential command. This function invokes the TPM2_ActivateCredential command in a one-call variant. This means the function will block until the TPM response is available. Args: activate_handle (ESYS_TR): Handle of the object associated with certificate in credentialBlob. key_handle (ESYS_TR): Loaded key used to decrypt the TPMS_SENSITIVE in credentialBlob. credential_blob (TPM2B_ID_OBJECT): The credential. secret (TPM2B_ENCRYPTED_SECRET): KeyHandle algorithm-dependent encrypted seed that protects credentialBlob. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: The cert_info, which is a TPM2B_DIGEST of the decrypted certificate information. C Function: Esys_ActivateCredential TPM Command: TPM2_ActivateCredential """ _check_handle_type(activate_handle, "activate_handle") _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") credential_blob_cdata = _get_cdata( credential_blob, TPM2B_ID_OBJECT, "credential_blob" ) secret_cdata = _get_cdata(secret, TPM2B_ENCRYPTED_SECRET, "secret") cert_info = ffi.new("TPM2B_DIGEST **") _chkrc( lib.Esys_ActivateCredential( self._ctx, activate_handle, key_handle, session1, session2, session3, credential_blob_cdata, secret_cdata, cert_info, ) ) return TPM2B_DIGEST(_get_dptr(cert_info, lib.Esys_Free)) def make_credential( self, handle: ESYS_TR, credential: TPM2B_DIGEST, object_name: TPM2B_NAME, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET]: """Invoke the TPM2_MakeCredential command. This function invokes the TPM2_MakeCredential command in a one-call variant. This means the function will block until the TPM response is available. Args: handle (ESYS_TR): Loaded public area, used to encrypt the sensitive area containing the credential key. credential (TPM2B_DIGEST): The credential information. object_name (TPM2B_NAME): Name of the object to which the credential applies. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET] which is the credential_blob and the secret portions respectively. The secret is a handle algorithm-dependent data that wraps the key that encrypts credential_blob. C Function: Esys_MakeCredential TPM Command: TPM2_MakeCredential """ _check_handle_type(handle, "handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") credential_cdata = _get_cdata(credential, TPM2B_DIGEST, "credential") object_name_cdata = _get_cdata(object_name, TPM2B_NAME, "object_name") credential_blob = ffi.new("TPM2B_ID_OBJECT **") secret = ffi.new("TPM2B_ENCRYPTED_SECRET **") _chkrc( lib.Esys_MakeCredential( self._ctx, handle, session1, session2, session3, credential_cdata, object_name_cdata, credential_blob, secret, ) ) return ( TPM2B_ID_OBJECT(_get_dptr(credential_blob, lib.Esys_Free)), TPM2B_ENCRYPTED_SECRET(_get_dptr(secret, lib.Esys_Free)), ) def unseal( self, item_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_SENSITIVE_DATA: """Invoke the TPM2_Unseal command. This function invokes the TPM2_Unseal command in a one-call variant. This means the function will block until the TPM response is available. Args: item_handle (ESYS_TR): The handle of a loaded data object. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_SENSITIVE_DATA which is the unsealed data. C Function: Esys_Unseal TPM Command: TPM2_Unseal """ _check_handle_type(item_handle, "item_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") out_data = ffi.new("TPM2B_SENSITIVE_DATA **") _chkrc( lib.Esys_Unseal( self._ctx, item_handle, session1, session2, session3, out_data ) ) return TPM2B_SENSITIVE_DATA(_get_dptr(out_data, lib.Esys_Free)) def object_change_auth( self, object_handle: ESYS_TR, parent_handle: ESYS_TR, new_auth: Union[TPM2B_AUTH, str, bytes], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_PRIVATE: """Invoke the TPM2_ObjectChangeAuth command. This function invokes the TPM2_ObjectChangeAuth command in a one-call variant. This means the function will block until the TPM response is available. Args: object_handle (ESYS_TR): Handle of the object. parent_handle (ESYS_TR): Handle of the parent. new_auth (Union[TPM2B_AUTH, str, bytes]): New authorization value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A new TPM2B_PRIVATE which includes the new_auth value. C Function: Esys_ObjectChangeAuth TPM Command: TPM2_ObjectChangeAuth """ _check_handle_type(object_handle, "object_handle") _check_handle_type(parent_handle, "parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") new_auth_cdata = _get_cdata(new_auth, TPM2B_AUTH, "new_auth") out_private = ffi.new("TPM2B_PRIVATE **") _chkrc( lib.Esys_ObjectChangeAuth( self._ctx, object_handle, parent_handle, session1, session2, session3, new_auth_cdata, out_private, ) ) return TPM2B_PRIVATE(_get_dptr(out_private, lib.Esys_Free)) def create_loaded( self, parent_handle: ESYS_TR, in_sensitive: Optional[TPM2B_SENSITIVE_CREATE], in_public: Union[TPM2B_TEMPLATE, str] = "rsa2048", session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[ESYS_TR, TPM2B_PRIVATE, TPM2B_PUBLIC]: """Invoke the TPM2_CreateLoaded command. This function invokes the TPM2_CreateLoaded command in a one-call variant. This means the function will block until the TPM response is available. Args: parent_handle (ESYS_TR): TPM2_Handle of a transient storage key, a persistent storage key, ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM+{PP}, or ESYS_TR.NULL. in_sensitive (TPM2B_SENSITIVE_CREATE): The sensitive data, see TPM 2.0 Part 1 Sensitive Values. Accepts None for an empty TPM2B_SENSITIVE_CREATE. in_public (Union[TPM2B_TEMPLATE, str]): The public template (optional). Defaults to an rsa2048 key. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[ESYS_TR, TPM2B_PRIVATE, TPM2B_PUBLIC] which is the handle of the loaded object(object_handle), the sensitive area of the object (out_private), and the public portion of the created object (out_public). C Function: Esys_CreateLoaded TPM Command: TPM2_CreateLoaded """ _check_handle_type(parent_handle, "parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") if isinstance(in_public, str): in_public = TPM2B_TEMPLATE(TPMT_PUBLIC.parse(in_public).marshal()) if in_sensitive is None: in_sensitive = TPM2B_SENSITIVE_CREATE() in_sensitive_cdata = _get_cdata( in_sensitive, TPM2B_SENSITIVE_CREATE, "in_sensitive" ) in_public_cdata = _get_cdata(in_public, TPM2B_TEMPLATE, "in_public") object_handle = ffi.new("ESYS_TR *") out_private = ffi.new("TPM2B_PRIVATE **") out_public = ffi.new("TPM2B_PUBLIC **") _chkrc( lib.Esys_CreateLoaded( self._ctx, parent_handle, session1, session2, session3, in_sensitive_cdata, in_public_cdata, object_handle, out_private, out_public, ) ) return ( ESYS_TR(object_handle[0], ectx=self), TPM2B_PRIVATE(_get_dptr(out_private, lib.Esys_Free)), TPM2B_PUBLIC(_get_dptr(out_public, lib.Esys_Free)), ) def duplicate( self, object_handle: ESYS_TR, new_parent_handle: ESYS_TR, encryption_key_in: TPM2B_DATA, symmetric_alg: TPMT_SYM_DEF_OBJECT, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_DATA, TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET]: """Invoke the TPM2_Duplicate command. This function invokes the TPM2_Duplicate command in a one-call variant. This means the function will block until the TPM response is available. Args: object_handle (ESYS_TR): Loaded object to duplicate. new_parent_handle (ESYS_TR): The duplication parent, and hall reference the public area of an asymmetric key. encryption_key_in (TPM2B_DATA): Symmetric encryption key. Can be None if no wrapping is to be performed. symmetric_alg (TPMT_SYM_DEF_OBJECT): Definition for the symmetric algorithm to be used for the inner wrapper session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_DATA, TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET] which is the TPM2_If the caller provided an encryption key or if symmetric_alg was TPM2_ALG.NULL, then this will be the TPM2_Empty TPM2_Buffer; otherwise, it shall contain the TPM2_TPM-generated, symmetric encryption key for the inner wrapper, duplicate Private area that may be encrypted by encryption_key_in; and may be doubly encrypted and the Seed protected by the asymmetric algorithms of new parent (NP). C Function: Esys_Duplicate TPM Command: TPM2_Duplicate """ _check_handle_type(object_handle, "object_handle") _check_handle_type(new_parent_handle, "new_parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") encryption_key_in_cdata = _get_cdata( encryption_key_in, TPM2B_DATA, "encryption_key_in", allow_none=True ) symmetric_alg_cdata = _get_cdata( symmetric_alg, TPMT_SYM_DEF_OBJECT, "symmetric_alg" ) encryption_key_out = ffi.new("TPM2B_DATA **") duplicate = ffi.new("TPM2B_PRIVATE **") out_sym_seed = ffi.new("TPM2B_ENCRYPTED_SECRET **") _chkrc( lib.Esys_Duplicate( self._ctx, object_handle, new_parent_handle, session1, session2, session3, encryption_key_in_cdata, symmetric_alg_cdata, encryption_key_out, duplicate, out_sym_seed, ) ) return ( TPM2B_DATA(_get_dptr(encryption_key_out, lib.Esys_Free)), TPM2B_PRIVATE(_get_dptr(duplicate, lib.Esys_Free)), TPM2B_ENCRYPTED_SECRET(_get_dptr(out_sym_seed, lib.Esys_Free)), ) def rewrap( self, old_parent: ESYS_TR, new_parent: ESYS_TR, in_duplicate: TPM2B_PRIVATE, name: Union[TPM2B_NAME, bytes, str], in_sym_seed: TPM2B_ENCRYPTED_SECRET, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET]: """Invoke the TPM2_Rewrap command. This function invokes the TPM2_Rewrap command in a one-call variant. This means the function will block until the TPM response is available. Args: old_parent (ESYS_TR): Parent of object. new_parent (ESYS_TR): New parent of the object. in_duplicate (TPM2B_PRIVATE): An object encrypted using symmetric key derived from inSymSeed. name (Union[TPM2B_NAME, bytes, str]): The Name of the object being rewrapped. in_sym_seed (TPM2B_ENCRYPTED_SECRET): The seed for the symmetric key and HMAC key. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET] which is the object encrypted using symmetric key derived from out_sym_seed and out_sym_seed which is the Seed for a symmetric key protected by newParent asymmetric key respecitevely. C Function: Esys_Rewrap TPM Command: TPM2_Rewrap """ _check_handle_type(old_parent, "old_parent") _check_handle_type(new_parent, "new_parent") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_duplicate_cdata = _get_cdata(in_duplicate, TPM2B_PRIVATE, "in_duplicate") in_sym_seed_cdata = _get_cdata( in_sym_seed, TPM2B_ENCRYPTED_SECRET, "in_sym_seed" ) name_cdata = _get_cdata(name, TPM2B_NAME, "name") out_duplicate = ffi.new("TPM2B_PRIVATE **") out_sym_seed = ffi.new("TPM2B_ENCRYPTED_SECRET **") _chkrc( lib.Esys_Rewrap( self._ctx, old_parent, new_parent, session1, session2, session3, in_duplicate_cdata, name_cdata, in_sym_seed_cdata, out_duplicate, out_sym_seed, ) ) return ( TPM2B_PRIVATE(_get_dptr(out_duplicate, lib.Esys_Free)), TPM2B_ENCRYPTED_SECRET(_get_dptr(out_sym_seed, lib.Esys_Free)), ) def import_( self, parent_handle: ESYS_TR, encryption_key: Union[TPM2B_DATA, bytes, str], object_public: TPM2B_PUBLIC, duplicate: TPM2B_PRIVATE, in_sym_seed: TPM2B_ENCRYPTED_SECRET, symmetric_alg: TPMT_SYM_DEF_OBJECT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_PRIVATE: """Invoke the TPM2_Import command. This function invokes the TPM2_Import command in a one-call variant. This means the function will block until the TPM response is available. Args: parent_handle (ESYS_TR): The handle of the new parent for the object. encryption_key (Union[TPM2B_DATA, bytes, str]): The optional symmetric encryption key used as the inner wrapper for duplicate. object_public (TPM2B_PUBLIC): The public area of the object to be imported. duplicate (TPM2B_PRIVATE): The symmetrically encrypted duplicate object that may contain an inner symmetric wrapper. in_sym_seed (TPM2B_ENCRYPTED_SECRET): The seed for the symmetric key and HMAC key. symmetric_alg (TPMT_SYM_DEF_OBJECT): Definition for the symmetric algorithm to use for the inner wrapper. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_PRIVATE which is the sensitive area encrypted with the symmetric key of parentHandle. C Function: Esys_Import TPM Command: TPM2_Import """ _check_handle_type(parent_handle, "parent_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") encryption_key_cdata = _get_cdata(encryption_key, TPM2B_DATA, "encryption_key") object_public_cdata = _get_cdata(object_public, TPM2B_PUBLIC, "object_public") duplicate_cdata = _get_cdata(duplicate, TPM2B_PRIVATE, "duplicate") in_sym_seed_cdata = _get_cdata( in_sym_seed, TPM2B_ENCRYPTED_SECRET, "in_sym_seed" ) symmetric_alg_cdata = _get_cdata( symmetric_alg, TPMT_SYM_DEF_OBJECT, "symmetric_alg" ) out_private = ffi.new("TPM2B_PRIVATE **") _chkrc( lib.Esys_Import( self._ctx, parent_handle, session1, session2, session3, encryption_key_cdata, object_public_cdata, duplicate_cdata, in_sym_seed_cdata, symmetric_alg_cdata, out_private, ) ) return TPM2B_PRIVATE(_get_dptr(out_private, lib.Esys_Free)) def rsa_encrypt( self, key_handle: ESYS_TR, message: Union[TPM2B_PUBLIC_KEY_RSA, bytes, str], in_scheme: TPMT_RSA_DECRYPT, label: Union[TPM2B_DATA, bytes, str, None] = None, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_PUBLIC_KEY_RSA: """Invoke the TPM2_RSA_Encrypt command. This function invokes the TPM2_RSA_Encrypt command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): Reference to public portion of RSA key to use for encryption. message (Union[TPM2B_PUBLIC_KEY_RSA, bytes, str]): Message to be encrypted. in_scheme (TPMT_RSA_DECRYPT): TPM2_The padding scheme to use if scheme associated with keyHandle is TPM2_ALG_NULL. label (Union[TPM2B_DATA, bytes, str, None]): label to be associated with the message (optional). Defaults to None. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_PUBLIC_KEY_RSA which is the encrypted output. C Function: Esys_RSA_Encrypt TPM Command: TPM2_RSA_Encrypt """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_scheme_cdata = _get_cdata(in_scheme, TPMT_RSA_DECRYPT, "in_scheme") message_cdata = _get_cdata(message, TPM2B_PUBLIC_KEY_RSA, "message") label_cdata = _get_cdata(label, TPM2B_DATA, "label", allow_none=True) out_data = ffi.new("TPM2B_PUBLIC_KEY_RSA **") _chkrc( lib.Esys_RSA_Encrypt( self._ctx, key_handle, session1, session2, session3, message_cdata, in_scheme_cdata, label_cdata, out_data, ) ) return TPM2B_PUBLIC_KEY_RSA(_get_dptr(out_data, lib.Esys_Free)) def rsa_decrypt( self, key_handle: ESYS_TR, cipher_text: Union[TPM2B_PUBLIC_KEY_RSA, bytes, str], in_scheme: TPMT_RSA_DECRYPT, label: Union[TPM2B_DATA, bytes, str, None] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_PUBLIC_KEY_RSA: """Invoke the TPM2_RSA_Decrypt command. This function invokes the TPM2_RSA_Decrypt command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): RSA key to use for decryption. cipher_text (Union[TPM2B_PUBLIC_KEY_RSA, bytes, str]): Cipher text to be decrypted. in_scheme (TPMT_RSA_DECRYPT): TPM2_The padding scheme to use if scheme associated with keyHandle is TPM2_ALG_NULL. label (Union[TPM2B_DATA, bytes, str, None]): whose association with the message is to be verified. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_PUBLIC_KEY_RSA which is the Decrypted output. C Function: Esys_RSA_Decrypt TPM Command: TPM2_RSA_Decrypt """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_scheme_cdata = _get_cdata(in_scheme, TPMT_RSA_DECRYPT, "in_scheme") cipher_text_cdata = _get_cdata(cipher_text, TPM2B_PUBLIC_KEY_RSA, "cipher_text") label_cdata = _get_cdata(label, TPM2B_DATA, "label", allow_none=True) message = ffi.new("TPM2B_PUBLIC_KEY_RSA **") _chkrc( lib.Esys_RSA_Decrypt( self._ctx, key_handle, session1, session2, session3, cipher_text_cdata, in_scheme_cdata, label_cdata, message, ) ) return TPM2B_PUBLIC_KEY_RSA(_get_dptr(message, lib.Esys_Free)) def ecdh_key_gen( self, key_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT]: """Invoke the TPM2_ECDH_KeyGen command. This function invokes the TPM2_ECDH_KeyGen command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): Handle of a loaded ECC key public area. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: :A Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT] which is the zPoint Results of P := h[de]Qs and pubPoint Generated ephemeral public point (Qe) respectively. C Function: Esys_ECDH_KeyGen TPM Command: TPM2_ECDH_KeyGen """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") z_point = ffi.new("TPM2B_ECC_POINT **") pub_point = ffi.new("TPM2B_ECC_POINT **") _chkrc( lib.Esys_ECDH_KeyGen( self._ctx, key_handle, session1, session2, session3, z_point, pub_point ) ) return ( TPM2B_ECC_POINT(_get_dptr(z_point, lib.Esys_Free)), TPM2B_ECC_POINT(_get_dptr(pub_point, lib.Esys_Free)), ) def ecdh_zgen( self, key_handle: ESYS_TR, in_point: TPM2B_ECC_POINT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_ECC_POINT: """Invoke the TPM2_ECDH_ZGen command. This function invokes the TPM2_ECDH_ZGen command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): Handle of a loaded ECC key. in_point (TPM2B_ECC_POINT): A public key. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_ECC_POINT which is the X and Y coordinates of the product of the multiplication Z = (xZ , yZ) := [hdS]QB. C Function: Esys_ECDH_ZGen TPM Command: TPM2_ECDH_ZGen """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_point_cdata = _get_cdata(in_point, TPM2B_ECC_POINT, "in_point") out_point = ffi.new("TPM2B_ECC_POINT **") _chkrc( lib.Esys_ECDH_ZGen( self._ctx, key_handle, session1, session2, session3, in_point_cdata, out_point, ) ) return TPM2B_ECC_POINT(_get_dptr(out_point, lib.Esys_Free)) def ecc_parameters( self, curve_id: TPM2_ECC_CURVE, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPMS_ALGORITHM_DETAIL_ECC: """Invoke the TPM2_ECC_Parameters command. This function invokes the TPM2_ECC_Parameters command in a one-call variant. This means the function will block until the TPM response is available. Args: curve_id (TPM2_ECC_CURVE): Parameter set selector. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMS_ALGORITHM_DETAIL_ECC ECC parameters for the selected curve. C Function: Esys_ECC_Parameters TPM Command: TPM2_ECC_Parameters """ _check_friendly_int(curve_id, "curve_id", TPM2_ECC_CURVE) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") parameters = ffi.new("TPMS_ALGORITHM_DETAIL_ECC **") _chkrc( lib.Esys_ECC_Parameters( self._ctx, session1, session2, session3, curve_id, parameters ) ) return TPMS_ALGORITHM_DETAIL_ECC(_get_dptr(parameters, lib.Esys_Free)) def zgen_2_phase( self, key_a: ESYS_TR, in_qs_b: TPM2B_ECC_POINT, in_qe_b: TPM2B_ECC_POINT, in_scheme: TPM2_ALG, counter: int, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT]: """Invoke the TPM2_ZGen_2Phase command. This function invokes the TPM2_ZGen_2Phase command in a one-call variant. This means the function will block until the TPM response is available. Args: key_a (ESYS_TR): Handle of an unrestricted decryption key ECC. in_qs_b (TPM2B_ECC_POINT): party's static public key (Qs,B = (Xs,B, Ys,B)). in_qe_b (TPM2B_ECC_POINT): party's ephemeral public key (Qe,B = (Xe,B, Ye,B)). in_scheme (TPM2_ALG): The key exchange scheme. counter (int): Value returned by TPM2_EC_Ephemeral(). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT] which are the X and Y coordinates of the first and second computed values (scheme dependent) respectively. C Function: Esys_ZGen_2Phase TPM Command: TPM2_ZGen_2Phase """ _check_handle_type(session1, "key_a") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(in_scheme, "in_scheme", TPM2_ALG) if not isinstance(counter, int): raise TypeError(f"Expected counter to be type int, got {type(counter)}") if counter < 0 or counter > 65535: raise ValueError( f"Expected counter to be in range of uint16_t, got {counter}" ) in_qs_b_cdata = _get_cdata(in_qs_b, TPM2B_ECC_POINT, "in_qs_b") in_qe_b_cdata = _get_cdata(in_qe_b, TPM2B_ECC_POINT, "in_qe_b") out_z1 = ffi.new("TPM2B_ECC_POINT **") out_z2 = ffi.new("TPM2B_ECC_POINT **") _chkrc( lib.Esys_ZGen_2Phase( self._ctx, key_a, session1, session2, session3, in_qs_b_cdata, in_qe_b_cdata, in_scheme, counter, out_z1, out_z2, ) ) return ( TPM2B_ECC_POINT(_get_dptr(out_z1, lib.Esys_Free)), TPM2B_ECC_POINT(_get_dptr(out_z2, lib.Esys_Free)), ) def encrypt_decrypt( self, key_handle: ESYS_TR, decrypt: bool, mode: TPM2_ALG, iv_in: Union[TPM2B_IV, bytes, str], in_data: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_MAX_BUFFER, TPM2B_IV]: """Invoke the TPM2_EncryptDecrypt command. This function invokes the TPM2_EncryptDecrypt command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): The symmetric key used for the operation. decrypt (bool): If True, then the operation is decryption; if False, the operation is encryption. mode (TPM2_ALG): Symmetric mode. iv_in (Union[TPM2B_IV, bytes, str]): An initial value as required by the algorithm. in_data (Union[TPM2B_MAX_BUFFER, bytes, str]): The data to be encrypted/decrypted. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_MAX_BUFFER, TPM2B_IV] which is the encrypted or decrypted output and the chaining value to use for IV in next round respectively. C Function: Esys_EncryptDecrypt TPM Command: TPM2_EncryptDecrypt """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(mode, "mode", TPM2_ALG) iv_in_cdata = _get_cdata(iv_in, TPM2B_IV, "iv_in") in_data_cdata = _get_cdata(in_data, TPM2B_MAX_BUFFER, "in_data") if not isinstance(decrypt, bool): raise TypeError(f"Expected decrypt to be type bool, got {type(decrypt)}") out_data = ffi.new("TPM2B_MAX_BUFFER **") iv_out = ffi.new("TPM2B_IV **") _chkrc( lib.Esys_EncryptDecrypt( self._ctx, key_handle, session1, session2, session3, decrypt, mode, iv_in_cdata, in_data_cdata, out_data, iv_out, ) ) return ( TPM2B_MAX_BUFFER(_get_dptr(out_data, lib.Esys_Free)), TPM2B_IV(_get_dptr(iv_out, lib.Esys_Free)), ) def encrypt_decrypt_2( self, key_handle: ESYS_TR, decrypt: bool, mode: TPM2_ALG, iv_in: Union[TPM2B_IV, bytes, str], in_data: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_MAX_BUFFER, TPM2B_IV]: """Invoke the TPM2_EncryptDecrypt2 command. This function invokes the TPM2_EncryptDecrypt2 command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): The symmetric key used for the operation. decrypt (bool): If True, then the operation is decryption; if False, the operation is encryption. mode (TPM2_ALG): Symmetric mode. iv_in (Union[TPM2B_IV, bytes, str]): An initial value as required by the algorithm. in_data (Union[TPM2B_MAX_BUFFER, bytes, str]): The data to be encrypted/decrypted. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_MAX_BUFFER, TPM2B_IV] which is the encrypted or decrypted output and the chaining value to use for IV in next round respectively. C Function: Esys_EncryptDecrypt2 TPM Command: TPM2_EncryptDecrypt2 """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(mode, "mode", TPM2_ALG) iv_in_cdata = _get_cdata(iv_in, TPM2B_IV, "iv_in") in_data_cdata = _get_cdata(in_data, TPM2B_MAX_BUFFER, "in_data") if not isinstance(decrypt, bool): raise TypeError("Expected decrypt to be type bool, got {type(decrypt)}") out_data = ffi.new("TPM2B_MAX_BUFFER **") iv_out = ffi.new("TPM2B_IV **") _chkrc( lib.Esys_EncryptDecrypt2( self._ctx, key_handle, session1, session2, session3, in_data_cdata, decrypt, mode, iv_in_cdata, out_data, iv_out, ) ) return ( TPM2B_MAX_BUFFER(_get_dptr(out_data, lib.Esys_Free)), TPM2B_IV(_get_dptr(iv_out, lib.Esys_Free)), ) def hash( self, data: Union[TPM2B_MAX_BUFFER, bytes, str], hash_alg: TPM2_ALG, hierarchy: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_DIGEST, TPMT_TK_HASHCHECK]: """Invoke the TPM2_Hash command. This function invokes the TPM2_Hash command in a one-call variant. This means the function will block until the TPM response is available. Args: data (Union[TPM2B_MAX_BUFFER, bytes, str]): Data to be hashed. hash_alg (TPM2_ALG): TPM2_Algorithm for the hash being computed - shall not be TPM2_ALG_NULL. hierarchy (ESYS_TR): Hierarchy to use for the ticket (ESYS_TR.NULL allowed). Defaults to ESYS_TR.OWNER. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_DIGEST, TPMT_TK_HASHCHECK] which is the hash and validation TPM2_Ticket indicating that the sequence of octets used to compute outDigest did not start with TPM2_GENERATED_VALUE respectively. C Function: Esys_Hash TPM Command: TPM2_Hash """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) _check_friendly_int(hierarchy, "hierarchy", ESYS_TR) hierarchy = ESAPI._fixup_hierarchy(hierarchy) data_cdata = _get_cdata(data, TPM2B_MAX_BUFFER, "data") out_hash = ffi.new("TPM2B_DIGEST **") validation = ffi.new("TPMT_TK_HASHCHECK **") _chkrc( lib.Esys_Hash( self._ctx, session1, session2, session3, data_cdata, hash_alg, hierarchy, out_hash, validation, ) ) return ( TPM2B_DIGEST(_get_dptr(out_hash, lib.Esys_Free)), TPMT_TK_HASHCHECK(_get_dptr(validation, lib.Esys_Free)), ) def hmac( self, handle: ESYS_TR, buffer: Union[TPM2B_MAX_BUFFER, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DIGEST: """Invoke the TPM2_HMAC command. This function invokes the TPM2_HMAC command in a one-call variant. This means the function will block until the TPM response is available. Args: handle (ESYS_TR): Handle for the symmetric signing key providing the HMAC key. buffer (Union[TPM2B_MAX_BUFFER, bytes, str]): HMAC data. hash_alg (TPM2_ALG): Algorithm to use for HMAC. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_DIGEST result of the HMAC. C Function: Esys_HMAC TPM Command: TPM2_HMAC """ _check_handle_type(handle, "handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) buffer_cdata = _get_cdata(buffer, TPM2B_MAX_BUFFER, "buffer") out_hMAC = ffi.new("TPM2B_DIGEST **") _chkrc( lib.Esys_HMAC( self._ctx, handle, session1, session2, session3, buffer_cdata, hash_alg, out_hMAC, ) ) return TPM2B_DIGEST(_get_dptr(out_hMAC, lib.Esys_Free)) def mac( self, handle: ESYS_TR, buffer: Union[TPM2B_MAX_BUFFER, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DIGEST: """Invoke the TPM2_MAC command. This function invokes the TPM2_MAC command in a one-call variant. This means the function will block until the TPM response is available. Args: handle (ESYS_TR): Handle for the symmetric signing key providing the HMAC key. buffer (Union[TPM2B_MAX_BUFFER, bytes, str]): MAC data. hash_alg (TPM2_ALG): Algorithm to use for MAC. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_DIGEST result of the MAC. C Function: Esys_MAC TPM Command: TPM2_MAC """ if not _lib_version_atleast("tss2-esys", "4.0.0"): raise NotImplementedError("MAC api not supported below ESAPI v4") _check_handle_type(handle, "handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) buffer_cdata = _get_cdata(buffer, TPM2B_MAX_BUFFER, "buffer") out_MAC = ffi.new("TPM2B_DIGEST **") _chkrc( lib.Esys_MAC( self._ctx, handle, session1, session2, session3, buffer_cdata, hash_alg, out_MAC, ) ) return TPM2B_DIGEST(_get_dptr(out_MAC, lib.Esys_Free)) def get_random( self, bytes_requested: int, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DIGEST: """Invoke the TPM2_GetRandom command. This function invokes the TPM2_GetRandom command in a one-call variant. This means the function will block until the TPM response is available. Args: bytes_requested (int): Number of octets to return. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_DIGEST of the random octets. C Function: Esys_GetRandom TPM Command: TPM2_GetRandom """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") if not isinstance(bytes_requested, int): raise TypeError( f"Expected bytes_requested type to be int, got {type(bytes_requested)}" ) random_bytes = ffi.new("TPM2B_DIGEST **") _chkrc( lib.Esys_GetRandom( self._ctx, session1, session2, session3, bytes_requested, random_bytes ) ) return TPM2B_DIGEST(_get_dptr(random_bytes, lib.Esys_Free)) def stir_random( self, in_data: Union[TPM2B_SENSITIVE_DATA, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_StirRandom command. This function invokes the TPM2_StirRandom command in a one-call variant. This means the function will block until the TPM response is available. Args: in_data (Union[TPM2B_SENSITIVE_DATA, bytes, str]): Additional information. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_StirRandom TPM Command: TPM2_StirRandom """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_data_cdata = _get_cdata(in_data, TPM2B_SENSITIVE_DATA, "in_data") _chkrc( lib.Esys_StirRandom(self._ctx, session1, session2, session3, in_data_cdata) ) def hmac_start( self, handle: ESYS_TR, auth: Union[TPM2B_AUTH, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_HMAC_Start command. This function invokes the TPM2_HMAC_Start command in a one-call variant. This means the function will block until the TPM response is available. Args: handle (ESYS_TR): Handle of an HMAC key. auth (Union[TPM2B_AUTH, bytes, str]): Authorization value for subsequent use of the sequence. hash_alg (TPM2_ALG): The hash algorithm to use for the HMAC. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR handle of ESYS resource for TPMI_DH_OBJECT. C Function: Esys_HMAC_Start TPM Command: TPM2_HMAC_Start """ _check_handle_type(handle, "handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) if auth is None: auth = TPM2B_AUTH() auth_cdata = _get_cdata(auth, TPM2B_AUTH, "auth") sequence_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_HMAC_Start( self._ctx, handle, session1, session2, session3, auth_cdata, hash_alg, sequence_handle, ) ) return ESYS_TR(sequence_handle[0], ectx=self) def mac_start( self, handle: ESYS_TR, auth: Union[TPM2B_AUTH, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_MAC_Start command. This function invokes the TPM2_MAC_Start command in a one-call variant. This means the function will block until the TPM response is available. Args: handle (ESYS_TR): Handle of an MAC key. auth (Union[TPM2B_AUTH, bytes, str]): Authorization value for subsequent use of the sequence. hash_alg (TPM2_ALG): The hash algorithm to use for the MAC. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR handle of ESYS resource for TPMI_DH_OBJECT. C Function: Esys_MAC_Start TPM Command: TPM2_MAC_Start """ if not _lib_version_atleast("tss2-esys", "4.0.0"): raise NotImplementedError("MAC api not supported below ESAPI v4") _check_handle_type(handle, "handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) if auth is None: auth = TPM2B_AUTH() auth_cdata = _get_cdata(auth, TPM2B_AUTH, "auth") sequence_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_MAC_Start( self._ctx, handle, session1, session2, session3, auth_cdata, hash_alg, sequence_handle, ) ) return ESYS_TR(sequence_handle[0], ectx=self) def hash_sequence_start( self, auth: Union[TPM2B_AUTH, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_HashSequenceStart command. This function invokes the TPM2_HashSequenceStart command in a one-call variant. This means the function will block until the TPM response is available. Args: auth (Union[TPM2B_AUTH, bytes, str]): Authorization value for subsequent use of the sequence. hash_alg (TPM2_ALG): The hash algorithm to use for the hash sequence. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR handle of ESYS resource for TPMI_DH_OBJECT. C Function: Esys_HashSequenceStart TPM Command: TPM2_HashSequenceStart """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) if auth is None: auth = TPM2B_AUTH() auth_cdata = _get_cdata(auth, TPM2B_AUTH, "auth") sequence_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_HashSequenceStart( self._ctx, session1, session2, session3, auth_cdata, hash_alg, sequence_handle, ) ) return ESYS_TR(sequence_handle[0], ectx=self) def sequence_update( self, sequence_handle: ESYS_TR, buffer: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_SequenceUpdate command. This function invokes the TPM2_SequenceUpdate command in a one-call variant. This means the function will block until the TPM response is available. Args: sequence_handle (ESYS_TR): Handle for the sequence object. buffer (Union[TPM2B_MAX_BUFFER, bytes, str]): Data to be added to hash. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_SequenceUpdate TPM Command: TPM2_SequenceUpdate """ _check_handle_type(sequence_handle, "sequence_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") buffer_cdata = _get_cdata(buffer, TPM2B_MAX_BUFFER, "buffer", allow_none=True) _chkrc( lib.Esys_SequenceUpdate( self._ctx, sequence_handle, session1, session2, session3, buffer_cdata ) ) def sequence_complete( self, sequence_handle: ESYS_TR, buffer: Union[TPM2B_MAX_BUFFER, bytes, str], hierarchy: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_DIGEST, TPMT_TK_HASHCHECK]: """Invoke the TPM2_SequenceComplete command. This function invokes the TPM2_SequenceComplete command in a one-call variant. This means the function will block until the TPM response is available. Args: sequence_handle (ESYS_TR): Authorization for the sequence. buffer (Union[TPM2B_MAX_BUFFER, bytes, str]): Data to be added to the hash/HMAC. hierarchy (ESYS_TR): Hierarchy of the ticket for a hash. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_DIGEST, TPMT_TK_HASHCHECK] which is the The returned HMAC or digest in a sized buffer and the TPM2_Ticket indicating that the sequence of octets used to compute outDigest did not start with TPM2_GENERATED_VALUE respectively. C Function: Esys_SequenceComplete TPM Command: TPM2_SequenceComplete """ _check_handle_type(sequence_handle, "sequence_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(hierarchy, "hierarchy", ESYS_TR) hierarchy = ESAPI._fixup_hierarchy(hierarchy) buffer_cdata = _get_cdata(buffer, TPM2B_MAX_BUFFER, "buffer", allow_none=True) result = ffi.new("TPM2B_DIGEST **") validation = ffi.new("TPMT_TK_HASHCHECK **") _chkrc( lib.Esys_SequenceComplete( self._ctx, sequence_handle, session1, session2, session3, buffer_cdata, hierarchy, result, validation, ) ) return ( TPM2B_DIGEST(_get_dptr(result, lib.Esys_Free)), TPMT_TK_HASHCHECK(_get_dptr(validation, lib.Esys_Free)), ) def event_sequence_complete( self, pcr_handle: ESYS_TR, sequence_handle: ESYS_TR, buffer: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPML_DIGEST_VALUES: """Invoke the TPM2_EventSequenceComplete command. This function invokes the TPM2_EventSequenceComplete command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_handle (ESYS_TR): PCR to be extended with the Event data. sequence_handle (ESYS_TR): Authorization for the sequence. buffer (Union[TPM2B_MAX_BUFFER, bytes, str]): Data to be added to the Event. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPML_DIGEST_VALUES a list of digests computed for the PCR. C Function: Esys_EventSequenceComplete TPM Command: TPM2_EventSequenceComplete """ _check_handle_type(sequence_handle, "sequence_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(pcr_handle, "pcr_handle", ESYS_TR) buffer_cdata = _get_cdata(buffer, TPM2B_MAX_BUFFER, "buffer", allow_none=True) results = ffi.new("TPML_DIGEST_VALUES **") _chkrc( lib.Esys_EventSequenceComplete( self._ctx, pcr_handle, sequence_handle, session1, session2, session3, buffer_cdata, results, ) ) return TPML_DIGEST_VALUES(_get_dptr(results, lib.Esys_Free)) def certify( self, object_handle: ESYS_TR, sign_handle: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_Certify command. This function invokes the TPM2_Certify command in a one-call variant. This means the function will block until the TPM response is available. Args: object_handle (ESYS_TR): Handle of the object to be certified. sign_handle (ESYS_TR): Handle of the key used to sign the attestation structure. qualifying_data (Union[TPM2B_DATA, bytes, str]): User provided qualifying data. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the structure that was signed, known as certify_info and the signature computed over certify_info. C Function: Esys_Certify TPM Command: TPM2_Certify """ _check_handle_type(object_handle, "object_handle") _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data" ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") certify_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_Certify( self._ctx, object_handle, sign_handle, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, certify_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(certify_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def certify_creation( self, sign_handle: ESYS_TR, object_handle: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], creation_hash: Union[TPM2B_DIGEST, bytes, str], in_scheme: TPMT_SIG_SCHEME, creation_ticket: TPMT_TK_CREATION, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_CertifyCreation command. This function invokes the TPM2_CertifyCreation command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the key that will sign the attestation block. object_handle (ESYS_TR): The object associated with the creation data. qualifying_data (Union[TPM2B_DATA, bytes, str]): User provided qualifying data. creation_hash (Union[TPM2B_DIGEST, bytes, str]): Hash of the creation data produced by TPM2_Create() or TPM2_CreatePrimary(). in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL. creation_ticket (TPMT_TK_CREATION): Ticket produced by TPM2_Create() or TPM2_CreatePrimary(). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the structure that was signed, known as certify_info and the signature computed over certify_info. C Function: Esys_CertifyCreation TPM Command: TPM2_CertifyCreation """ _check_handle_type(object_handle, "object_handle") _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data" ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") creation_hash_cdata = _get_cdata(creation_hash, TPM2B_DIGEST, "creation_hash") creation_ticket_cdata = _get_cdata( creation_ticket, TPMT_TK_CREATION, "creation_ticket" ) certify_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_CertifyCreation( self._ctx, sign_handle, object_handle, session1, session2, session3, qualifying_data_cdata, creation_hash_cdata, in_scheme_cdata, creation_ticket_cdata, certify_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(certify_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def quote( self, sign_handle: ESYS_TR, pcr_select: Union[TPML_PCR_SELECTION, str], qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME = TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_Quote command. This function invokes the TPM2_Quote command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of key that will perform signature. pcr_select (Union[TPML_PCR_SELECTION, str]): PCR set to quote. qualifying_data (Union[TPM2B_DATA, bytes, str]): Data supplied by the caller. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL (optional). Defaults to TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the quoted information, known as quoted and the signature over quoted. C Function: Esys_Quote TPM Command: TPM2_Quote """ _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data" ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") PCRselect_cdata = _get_cdata(pcr_select, TPML_PCR_SELECTION, "pcr_select") quoted = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_Quote( self._ctx, sign_handle, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, PCRselect_cdata, quoted, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(quoted, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def get_session_audit_digest( self, sign_handle: ESYS_TR, session_handle: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME = TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), privacy_admin_handle: ESYS_TR = ESYS_TR.ENDORSEMENT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_GetSessionAuditDigest command. This function invokes the TPM2_GetSessionAuditDigest command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the signing key. session_handle (ESYS_TR): Handle of the audit session. qualifying_data (Union[TPM2B_DATA, bytes, str]): User-provided qualifying data - may be zero-length. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL (optional). Defaults to TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL). privacy_admin_handle (ESYS_TR): TPM2_Handle of the privacy administrator must be ESYS_TR.ENDORSEMENT. Defaults to ESYS_TR.ENDORSEMENT (optional). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the audit information that was signed, known as audit_info, and the signature over audit_info. C Function: Esys_GetSessionAuditDigest TPM Command: TPM2_GetSessionAuditDigest """ _check_handle_type(session_handle, "session_handle") _check_handle_type( privacy_admin_handle, "privacy_admin_handle", expected=[ESYS_TR.ENDORSEMENT], ) _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data", allow_none=True ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") audit_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_GetSessionAuditDigest( self._ctx, privacy_admin_handle, sign_handle, session_handle, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, audit_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(audit_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def get_command_audit_digest( self, sign_handle: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME = TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), privacy_handle: ESYS_TR = ESYS_TR.ENDORSEMENT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_GetCommandAuditDigest command. This function invokes the TPM2_GetCommandAuditDigest command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the signing key. qualifying_data (Union[TPM2B_DATA, bytes, str]): Other data to associate with this audit digest. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL (optional). Defaults to TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL). privacy_handle (ESYS_TR): TPM2_Handle of the privacy administrator must be ESYS_TR.ENDORSEMENT. Defaults to ESYS_TR.ENDORSEMENT (optional). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the audit information that was signed, known as audit_info, and the signature over audit_info. C Function: Esys_GetCommandAuditDigest TPM Command: TPM2_GetCommandAuditDigest """ _check_handle_type( privacy_handle, "privacy_handle", expected=[ESYS_TR.ENDORSEMENT] ) _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data", allow_none=True ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") audit_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_GetCommandAuditDigest( self._ctx, privacy_handle, sign_handle, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, audit_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(audit_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def get_time( self, sign_handle: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME = TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), privacy_admin_handle: ESYS_TR = ESYS_TR.ENDORSEMENT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_GetTime command. This function invokes the TPM2_GetTime command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the signing key. qualifying_data (Union[TPM2B_DATA, bytes, str]): Other data to associate with this audit digest. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG_NULL (optional). Defaults to TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL). privacy_admin_handle (ESYS_TR): TPM2_Handle of the privacy administrator must be ESYS_TR.ENDORSEMENT. Defaults to ESYS_TR.ENDORSEMENT (optional). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] Standard TPM-generated attestation block, known as time_info, and the signature over time_info respectively. C Function: Esys_GetTime TPM Command: TPM2_GetTime """ _check_handle_type( privacy_admin_handle, "privacy_admin_handle", expected=[ESYS_TR.ENDORSEMENT] ) _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data", allow_none=True ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") time_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_GetTime( self._ctx, privacy_admin_handle, sign_handle, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, time_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(time_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def certify_x509( self, object_handle: ESYS_TR, sign_handle: ESYS_TR, partial_certificate: TPM2B_MAX_BUFFER, in_scheme: TPMT_SIG_SCHEME = TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_MAX_BUFFER, TPM2B_DIGEST, TPMT_SIGNATURE]: """Invoke the TPM2_CertifyX509 command. This function invokes the TPM2_CertifyX509 command in a one-call variant. This means the function will block until the TPM response is available. Args: object_handle (ESYS_TR): Handle of the object to be certified. sign_handle (ESYS_TR): Handle of the key used to sign the attestation structure. partial_certificate (TPM2B_MAX_BUFFER): A DER encoded partial certificate. in_scheme: (TPMT_SIG_SCHEME): The signing scheme to be used (optional), Defaults to a TPM2_ALG.NULL scheme. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_MAX_BUFFER, TPM2B_DIGEST, TPMT_SIGNATURE] which contains the DER encoded data, the signed digest and the signature. C Function: Esys_CertifyX509 TPM Command: TPM2_CertifyX509 """ if not _lib_version_atleast("tss2-esys", "3.1.0"): raise NotImplementedError("certify_x509 requires tss2-esys 3.1.0 or higher") _check_handle_type(object_handle, "object_handle") _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") reserved = TPM2B_DATA() reserved_cdata = _get_cdata(reserved, TPM2B_DATA, "reserved") in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") partial_certificate_cdata = _get_cdata( partial_certificate, TPM2B_MAX_BUFFER, "partial_certificate" ) added_to_certificate = ffi.new("TPM2B_MAX_BUFFER **") tbs_digest = ffi.new("TPM2B_DIGEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_CertifyX509( self._ctx, object_handle, sign_handle, session1, session2, session3, reserved_cdata, in_scheme_cdata, partial_certificate_cdata, added_to_certificate, tbs_digest, signature, ) ) return ( TPM2B_MAX_BUFFER(_get_dptr(added_to_certificate, lib.Esys_Free)), TPM2B_DIGEST(_get_dptr(tbs_digest, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def commit( self, sign_handle: ESYS_TR, p1: TPM2B_ECC_POINT, s2: Union[TPM2B_SENSITIVE_DATA, bytes, str], y2: Union[TPM2B_ECC_PARAMETER, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT, TPM2B_ECC_POINT, int]: """Invoke the TPM2_Commit command. This function invokes the TPM2_Commit command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the key that will be used in the signing operation p1 (TPM2B_ECC_POINT): A point (M) on the curve used by signHandle. s2 (Union[TPM2B_SENSITIVE_DATA, bytes, str]): Octet array used to derive x-coordinate of a base point. y2 (Union[TPM2B_ECC_PARAMETER, bytes, str]): Y coordinate of the point associated with s2. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ECC_POINT, TPM2B_ECC_POINT, TPM2B_ECC_POINT, int] which is the K point as ECC point K := [ds](x2, y2), the L point as L := [r](x2, y2), the E point as E := [r]P1 and the counter value respectively. C Function: Esys_Commit TPM Command: TPM2_Commit """ _check_handle_type(sign_handle, "sign_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") P1_cdata = _get_cdata(p1, TPM2B_ECC_POINT, "p1") s2_cdata = _get_cdata(s2, TPM2B_SENSITIVE_DATA, "s2") y2_cdata = _get_cdata(y2, TPM2B_ECC_PARAMETER, "y2") K = ffi.new("TPM2B_ECC_POINT **") L = ffi.new("TPM2B_ECC_POINT **") E = ffi.new("TPM2B_ECC_POINT **") counter = ffi.new("UINT16 *") _chkrc( lib.Esys_Commit( self._ctx, sign_handle, session1, session2, session3, P1_cdata, s2_cdata, y2_cdata, K, L, E, counter, ) ) return ( TPM2B_ECC_POINT(_get_dptr(K, lib.Esys_Free)), TPM2B_ECC_POINT(_get_dptr(L, lib.Esys_Free)), TPM2B_ECC_POINT(_get_dptr(E, lib.Esys_Free)), counter[0], ) def ec_ephemeral( self, curve_id: TPM2_ECC_CURVE, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ECC_POINT, int]: """Invoke the TPM2_EC_Ephemeral command. This function invokes the TPM2_EC_Ephemeral command in a one-call variant. This means the function will block until the TPM response is available. Args: curve_id (TPM2_ECC_CURVE): The curve for the computed ephemeral point. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: :A Tuple[TPM2B_ECC_POINT, int] which is the Ephemeral public key Q := [r]G, known as Q, and the least-significant 16 bits of commitCount. C Function: Esys_EC_Ephemeral TPM Command: TPM2_EC_Ephemeral """ _check_friendly_int(curve_id, "curve_id", TPM2_ECC_CURVE) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") Q = ffi.new("TPM2B_ECC_POINT **") counter = ffi.new("UINT16 *") _chkrc( lib.Esys_EC_Ephemeral( self._ctx, session1, session2, session3, curve_id, Q, counter ) ) return (TPM2B_ECC_POINT(_get_dptr(Q, lib.Esys_Free)), counter[0]) def verify_signature( self, key_handle: ESYS_TR, digest: Union[TPM2B_DIGEST, bytes, str], signature: TPMT_SIGNATURE, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPMT_TK_VERIFIED: """Invoke the TPM2_VerifySignature command. This function invokes the TPM2_VerifySignature command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): Handle of public key that will be used in the validation. digest (Union[TPM2B_DIGEST, bytes, str]): Digest of the signed message. signature (TPMT_SIGNATURE): Signature to be tested. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMT_TK_VERIFIED on successful verification of the signature. C Function: Esys_VerifySignature TPM Command: TPM2_VerifySignature """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") digest_cdata = _get_cdata(digest, TPM2B_DIGEST, "digest") signature_cdata = _get_cdata(signature, TPMT_SIGNATURE, "signature") validation = ffi.new("TPMT_TK_VERIFIED **") _chkrc( lib.Esys_VerifySignature( self._ctx, key_handle, session1, session2, session3, digest_cdata, signature_cdata, validation, ) ) return TPMT_TK_VERIFIED(_get_dptr(validation, lib.Esys_Free)) def sign( self, key_handle: ESYS_TR, digest: Union[TPM2B_DIGEST, bytes, str], in_scheme: TPMT_SIG_SCHEME, validation: Optional[TPMT_TK_HASHCHECK] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPMT_SIGNATURE: """Invoke the TPM2_Sign command. This function invokes the TPM2_Sign command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): digest (Union[TPM2B_DIGEST, bytes, str]): Digest to be signed. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for keyHandle is TPM2_ALG_NULL. validation (TPMT_TK_HASHCHECK, optional): Proof that digest was created by the TPM, defaults to NULL ticket. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMT_SIGNATURE the signature. C Function: Esys_Sign TPM Command: TPM2_Sign """ _check_handle_type(key_handle, "key_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") if validation is None: validation = TPMT_TK_HASHCHECK( tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL ) digest_cdata = _get_cdata(digest, TPM2B_DIGEST, "digest") in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") validation_cdata = _get_cdata(validation, TPMT_TK_HASHCHECK, "validation") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_Sign( self._ctx, key_handle, session1, session2, session3, digest_cdata, in_scheme_cdata, validation_cdata, signature, ) ) return TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)) def set_command_code_audit_status( self, audit_alg: TPM2_ALG, set_list: TPML_CC, clear_list: TPML_CC, auth: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_SetCommandCodeAuditStatus command. This function invokes the TPM2_SetCommandCodeAuditStatus command in a one-call variant. This means the function will block until the TPM response is available. Args: audit_alg (TPM2_ALG): TPM2_Hash algorithm for the audit digest; if TPM2_ALG_NULL, then the hash is not changed. set_list (TPML_CC): List of commands that will be added to those that will be audited. clear_list (TPML_CC): List of commands that will no longer be audited. auth (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP} (optional). Default to ESYS_TR.OWNER session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_SetCommandCodeAuditStatus TPM Command: TPM2_SetCommandCodeAuditStatus """ _check_handle_type(auth, "auth", expected=[ESYS_TR.OWNER, ESYS_TR.PLATFORM]) _check_friendly_int(audit_alg, "audit_alg", TPM2_ALG) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") set_list_cdata = _get_cdata(set_list, TPML_CC, "set_list") clear_list_cdata = _get_cdata(clear_list, TPML_CC, "digest") _chkrc( lib.Esys_SetCommandCodeAuditStatus( self._ctx, auth, session1, session2, session3, audit_alg, set_list_cdata, clear_list_cdata, ) ) def pcr_extend( self, pcr_handle: ESYS_TR, digests: TPML_DIGEST_VALUES, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PCR_Extend command. This function invokes the TPM2_PCR_Extend command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_handle (ESYS_TR): Handle of the PCR. digests (TPML_DIGEST_VALUES): List of tagged digest values to be extended. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PCR_Extend TPM Command: TPM2_PCR_Extend """ _check_handle_type(pcr_handle, "pcr_handle") digests_cdata = _get_cdata(digests, TPML_DIGEST_VALUES, "digests") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PCR_Extend( self._ctx, pcr_handle, session1, session2, session3, digests_cdata ) ) def pcr_event( self, pcr_handle: ESYS_TR, event_data: Union[TPM2B_EVENT, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPML_DIGEST_VALUES: """Invoke the TPM2_PCR_Event command. This function invokes the TPM2_PCR_Event command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_handle (ESYS_TR): Handle of the PCR. event_data (Union[TPM2B_EVENT, bytes, str]): The event data. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPML_DIGEST_VALUES the digests. C Function: Esys_PCR_Event TPM Command: TPM2_PCR_Event """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_handle_type(pcr_handle, "pcr_handle") event_data_cdata = _get_cdata(event_data, TPM2B_EVENT, "event_data") digests = ffi.new("TPML_DIGEST_VALUES **") _chkrc( lib.Esys_PCR_Event( self._ctx, pcr_handle, session1, session2, session3, event_data_cdata, digests, ) ) return TPML_DIGEST_VALUES(_get_dptr(digests, lib.Esys_Free)) def pcr_read( self, pcr_selection_in: Union[TPML_PCR_SELECTION, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[int, TPML_PCR_SELECTION, TPML_DIGEST]: """Invoke the TPM2_PCR_Read command. This function invokes the TPM2_PCR_Read command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_selection_in (Union[TPML_PCR_SELECTION, str]): The selection of PCR to read. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[int, TPML_PCR_SELECTION, TPML_DIGEST] of the current value of the PCR update counter, the digests The PCR in the returned list and the contents of the PCR indicated in TPML_PCR_SELECTION. C Function: Esys_PCR_Read TPM Command: TPM2_PCR_Read """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") pcr_selection_in_cdata = _get_cdata( pcr_selection_in, TPML_PCR_SELECTION, "pcr_selection_in" ) pcr_update_counter = ffi.new("UINT32 *") pcr_selection_out = ffi.new("TPML_PCR_SELECTION **") pcr_values = ffi.new("TPML_DIGEST **") _chkrc( lib.Esys_PCR_Read( self._ctx, session1, session2, session3, pcr_selection_in_cdata, pcr_update_counter, pcr_selection_out, pcr_values, ) ) return ( pcr_update_counter[0], TPML_PCR_SELECTION(_cdata=_get_dptr(pcr_selection_out, lib.Esys_Free)), TPML_DIGEST(_cdata=_get_dptr(pcr_values, lib.Esys_Free)), ) def pcr_allocate( self, pcr_allocation: Union[TPML_PCR_SELECTION, str], auth_handle: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[bool, int, int, int]: """Invoke the TPM2_PCR_Allocate command. This function invokes the TPM2_PCR_Allocate command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_allocation (Union[TPML_PCR_SELECTION, str]): The requested allocation. auth_handle (ESYS_TR): ESYS_TR.PLATFORM+{PP} (optional). Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[bool, int, int, int] of True if the allocation succeeded, the maximum number of PCR that may be in a bank, the number of octets required to satisfy the request, and number of octets available (Computed before the allocation) respectively. C Function: Esys_PCR_Allocate TPM Command: TPM2_PCR_Allocate """ _check_handle_type(auth_handle, "auth_handle", expected=[ESYS_TR.PLATFORM]) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") pcr_allocation_cdata = _get_cdata( pcr_allocation, TPML_PCR_SELECTION, "pcr_allocation" ) allocation_success = ffi.new("TPMI_YES_NO *") max_pCR = ffi.new("UINT32 *") size_needed = ffi.new("UINT32 *") size_available = ffi.new("UINT32 *") _chkrc( lib.Esys_PCR_Allocate( self._ctx, auth_handle, session1, session2, session3, pcr_allocation_cdata, allocation_success, max_pCR, size_needed, size_available, ) ) return ( bool(allocation_success[0]), max_pCR[0], size_needed[0], size_available[0], ) def pcr_set_auth_policy( self, auth_policy: Union[TPM2B_DIGEST, bytes, str], hash_alg: TPM2_ALG, pcr_num: ESYS_TR, auth_handle: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PCR_SetAuthPolicy command. This function invokes the TPM2_PCR_SetAuthPolicy command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_policy (Union[TPM2B_DIGEST, bytes, str]): The desired authPolicy. hash_alg (TPM2_ALG): The hash algorithm of the policy. pcr_num (ESYS_TR): The PCR for which the policy is to be set. auth_handle (ESYS_TR): ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PCR_SetAuthPolicy TPM Command: TPM2_PCR_SetAuthPolicy """ _check_handle_type(auth_handle, "auth_handle", expected=[ESYS_TR.PLATFORM]) _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) _check_friendly_int(pcr_num, "pcr_num", ESYS_TR) auth_policy_cdata = _get_cdata(auth_policy, TPM2B_DIGEST, "auth_policy") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PCR_SetAuthPolicy( self._ctx, auth_handle, session1, session2, session3, auth_policy_cdata, hash_alg, pcr_num, ) ) def pcr_set_auth_value( self, pcr_handle: ESYS_TR, auth: Union[TPM2B_DIGEST, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PCR_SetAuthValue command. This function invokes the TPM2_PCR_SetAuthValue command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_handle (ESYS_TR): Handle for a PCR that may have an authorization value set. auth (Union[TPM2B_DIGEST, bytes, str]): The desired authorization value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PCR_SetAuthValue TPM Command: TPM2_PCR_SetAuthValue """ _check_friendly_int(pcr_handle, "pcr_handle", ESYS_TR) auth_cdata = _get_cdata(auth, TPM2B_DIGEST, "auth") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PCR_SetAuthValue( self._ctx, pcr_handle, session1, session2, session3, auth_cdata ) ) def pcr_reset( self, pcr_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PCR_Reset command. This function invokes the TPM2_PCR_Reset command in a one-call variant. This means the function will block until the TPM response is available. Args: pcr_handle (ESYS_TR): The PCR to reset. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PCR_Reset TPM Command: TPM2_PCR_Reset """ _check_friendly_int(pcr_handle, "pcr_handle", ESYS_TR) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc(lib.Esys_PCR_Reset(self._ctx, pcr_handle, session1, session2, session3)) def policy_signed( self, auth_object: ESYS_TR, policy_session: ESYS_TR, auth: TPMT_SIGNATURE, nonce_tpm: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), cp_hash_a: Union[TPM2B_DIGEST, bytes, str] = TPM2B_DIGEST(), policy_ref: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), expiration: int = TPM2_MAX_EXPIRATION, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_TIMEOUT, TPMT_TK_AUTH]: """Invoke the TPM2_PolicySigned command. This function invokes the TPM2_PolicySigned command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_object (ESYS_TR): Handle for a key that will validate the signature. policy_session (ESYS_TR): Handle for the policy session being extended. auth (TPMT_SIGNATURE): Signed authorization (not optional). nonce_tpm (Union[TPM2B_NONCE, bytes, str]): The policy nonce for the session (optional). Defaults to an empty buffer. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited (optional). Defaults to an empty buffer. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer (optional). Defaults to an empty buffer. expiration (int): Time when authorization will expire, measured in seconds from the time that nonceTPM was generated (optional). Defaults to the max expiration value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_TIMEOUT, TPMT_TK_AUTH] which is the timeout, an implementation-specific time value, used to indicate to the TPM when the ticket expires and the policy_ticket, a which is produced if the command succeeds and expiration in the command was non-zero; this ticket will use the TPMT_ST_AUTH_SIGNED structure tag. See 23.2.5. C Function: Esys_PolicySigned TPM Command: TPM2_PolicySigned """ _check_handle_type(auth_object, "auth_object") _check_handle_type(policy_session, "policy_session") if not isinstance(expiration, int): raise TypeError( f"expected expiration to be type int, got {type(expiration)}" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") nonce_tpm_cdata = _get_cdata(nonce_tpm, TPM2B_NONCE, "nonce_tpm") cp_hash_a_cdata = _get_cdata(cp_hash_a, TPM2B_DIGEST, "cp_hash_a") policy_ref_cdata = _get_cdata(policy_ref, TPM2B_NONCE, "policy_ref") auth_cdata = _get_cdata(auth, TPMT_SIGNATURE, "auth") timeout = ffi.new("TPM2B_TIMEOUT **") policy_ticket = ffi.new("TPMT_TK_AUTH **") _chkrc( lib.Esys_PolicySigned( self._ctx, auth_object, policy_session, session1, session2, session3, nonce_tpm_cdata, cp_hash_a_cdata, policy_ref_cdata, expiration, auth_cdata, timeout, policy_ticket, ) ) return ( TPM2B_TIMEOUT(_get_dptr(timeout, lib.Esys_Free)), TPMT_TK_AUTH(_get_dptr(policy_ticket, lib.Esys_Free)), ) def policy_secret( self, auth_handle: ESYS_TR, policy_session: ESYS_TR, nonce_tpm: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), cp_hash_a: Union[TPM2B_DIGEST, bytes, str] = TPM2B_DIGEST(), policy_ref: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), expiration: int = TPM2_MAX_EXPIRATION, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_TIMEOUT, TPMT_TK_AUTH]: """Invoke the TPM2_PolicySecret command. This function invokes the TPM2_PolicySecret command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): Handle for an entity providing the authorization. policy_session (ESYS_TR): Handle for the policy session being extended. nonce_tpm (Union[TPM2B_NONCE, bytes, str]): The policy nonce for the session (optional). Defaults to an empty buffer. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited (optional). Defaults to an empty buffer. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer (optional). Defaults to an empty buffer. expiration (int): Time when authorization will expire, measured in seconds from the time that nonceTPM was generated (optional). Defaults to the max expiration value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_TIMEOUT, TPMT_TK_AUTH] which is the timeout, an implementation-specific time value, used to indicate to the TPM when the ticket expires and the policy_ticket, a which is produced if the command succeeds and expiration in the command was non-zero; this ticket will use the TPMT_ST_AUTH_SIGNED structure tag. See 23.2.5. C Function: Esys_PolicySecret TPM Command: TPM2_PolicySecret """ _check_handle_type(policy_session, "policy_session") if not isinstance(expiration, int): raise TypeError( f"expected expiration to be type int, got {type(expiration)}" ) _check_handle_type(auth_handle, "auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") nonce_tPM_cdata = _get_cdata(nonce_tpm, TPM2B_NONCE, "nonce_tpm") cp_hash_a_cdata = _get_cdata(cp_hash_a, TPM2B_DIGEST, "cp_hash_a") policy_ref_cdata = _get_cdata(policy_ref, TPM2B_NONCE, "policy_ref") timeout = ffi.new("TPM2B_TIMEOUT **") policy_ticket = ffi.new("TPMT_TK_AUTH **") _chkrc( lib.Esys_PolicySecret( self._ctx, auth_handle, policy_session, session1, session2, session3, nonce_tPM_cdata, cp_hash_a_cdata, policy_ref_cdata, expiration, timeout, policy_ticket, ) ) return ( TPM2B_TIMEOUT(_get_dptr(timeout, lib.Esys_Free)), TPMT_TK_AUTH(_get_dptr(policy_ticket, lib.Esys_Free)), ) def policy_ticket( self, policy_session: ESYS_TR, timeout: TPM2B_TIMEOUT, auth_name: Union[TPM2B_NAME, bytes, str], ticket: TPMT_TK_AUTH, cp_hash_a: Union[TPM2B_DIGEST, bytes, str] = TPM2B_DIGEST(), policy_ref: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyTicket command. This function invokes the TPM2_PolicyTicket command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. timeout (TPM2B_TIMEOUT): Time when authorization will expire. auth_name (Union[TPM2B_NAME, bytes, str]): Name of the object that provided the authorization. ticket (TPMT_TK_AUTH): An authorization ticket returned by the TPM in response to a TPM2_PolicySigned() or TPM2_PolicySecret(). cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited (optional). Defaults to an empty buffer. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer (optional). Defaults to an empty buffer. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyTicket TPM Command: TPM2_PolicyTicket """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") timeout_cdata = _get_cdata(timeout, TPM2B_TIMEOUT, "timeout") cp_hash_a_cdata = _get_cdata(cp_hash_a, TPM2B_DIGEST, "cp_hash_a") policy_ref_cdata = _get_cdata(policy_ref, TPM2B_NONCE, "policy_ref") auth_name_cdata = _get_cdata(auth_name, TPM2B_NAME, "auth_name") ticket_cdata = _get_cdata(ticket, TPMT_TK_AUTH, "ticket") _chkrc( lib.Esys_PolicyTicket( self._ctx, policy_session, session1, session2, session3, timeout_cdata, cp_hash_a_cdata, policy_ref_cdata, auth_name_cdata, ticket_cdata, ) ) def policy_or( self, policy_session: ESYS_TR, p_hash_list: TPML_DIGEST, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyOr command. This function invokes the TPM2_PolicyOr command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. p_hash_list (TPML_DIGEST): The list of hashes to check for a match. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyOr TPM Command: TPM2_PolicyOr """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") p_hash_list_cdata = _get_cdata(p_hash_list, TPML_DIGEST, "p_hash_list") _chkrc( lib.Esys_PolicyOR( self._ctx, policy_session, session1, session2, session3, p_hash_list_cdata, ) ) def policy_pcr( self, policy_session: ESYS_TR, pcr_digest: Union[TPM2B_DIGEST, bytes, str, None], pcrs: Union[TPML_PCR_SELECTION, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyPCR command. This function invokes the TPM2_PolicyPCR command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. pcr_digest (Union[TPM2B_DIGEST, bytes, str, None]): Expected digest value of the selected PCR using the hash algorithm of the session; may be zero length or None. pcrs (Union[TPML_PCR_SELECTION, str]): The PCR to include in the check digest. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyPCR TPM Command: TPM2_PolicyPCR """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") pcr_digest_cdata = _get_cdata( pcr_digest, TPM2B_DIGEST, "pcr_digest", allow_none=True ) pcrs_cdata = _get_cdata(pcrs, TPML_PCR_SELECTION, "pcrs") _chkrc( lib.Esys_PolicyPCR( self._ctx, policy_session, session1, session2, session3, pcr_digest_cdata, pcrs_cdata, ) ) def policy_locality( self, policy_session: ESYS_TR, locality: int, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyLocality command. This function invokes the TPM2_PolicyLocality command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. locality (int): The allowed localities for the policy. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyLocality TPM Command: TPM2_PolicyLocality """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") if not isinstance(locality, int): raise TypeError( f"Expected locality to be of type TPMA_LOCALITY aka int, got {type(locality)}" ) # Locality of 0-4 are indicated as bit index 0-4 being set. Localities 32-255 are # indicated as values. Thus locality of 0 is invalid, along with values greater than # 1 byte (255). if locality < 1 or locality > 255: raise ValueError( f"Expected locality to be in range of 1 - 255, got {locality}" ) _chkrc( lib.Esys_PolicyLocality( self._ctx, policy_session, session1, session2, session3, locality ) ) def policy_nv( self, auth_handle: ESYS_TR, nv_index: ESYS_TR, policy_session: ESYS_TR, operand_b: TPM2B_OPERAND, operation: TPM2_EO, offset: int = 0, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyNV command. This function invokes the TPM2_PolicyNV command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): Handle indicating the source of the authorization value. nv_index (ESYS_TR): The NV Index of the area to read. policy_session (ESYS_TR): Handle for the policy session being extended. operand_b (TPM2B_OPERAND): The second operand. operation (TPM2_EO): The comparison to make. offset (int): The offset in the NV Index for the start of operand A. (optional). Defaults to 0. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyNV TPM Command: TPM2_PolicyNV """ _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(policy_session, "policy_session") operand_b_cdata = _get_cdata(operand_b, TPM2B_OPERAND, "operand_b") _check_friendly_int(operation, "operation", TPM2_EO) if not isinstance(offset, int): raise TypeError(f"Expected offset to be of type int, got {type(offset)}") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyNV( self._ctx, auth_handle, nv_index, policy_session, session1, session2, session3, operand_b_cdata, offset, operation, ) ) def policy_counter_timer( self, policy_session: ESYS_TR, operand_b: TPM2B_OPERAND, operation: TPM2_EO, offset: int = 0, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyCounterTimer command. This function invokes the TPM2_PolicyCounterTimer command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. operand_b (TPM2B_OPERAND): The second operand. operation (TPM2_EO): The comparison to make. offset (int): The offset in TPMS_TIME_INFO structure for the start of operand A. (optional). Defaults to 0. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyCounterTimer TPM Command: TPM2_PolicyCounterTimer """ _check_handle_type(policy_session, "policy_session") operand_b_cdata = _get_cdata(operand_b, TPM2B_OPERAND, "operand_b") _check_friendly_int(operation, "operation", TPM2_EO) if not isinstance(offset, int): raise TypeError(f"Expected offset to be of type int, got {type(offset)}") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyCounterTimer( self._ctx, policy_session, session1, session2, session3, operand_b_cdata, offset, operation, ) ) def policy_command_code( self, policy_session: ESYS_TR, code: TPM2_CC, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyCommandCode command. This function invokes the TPM2_PolicyCommandCode command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. code (TPM2_CC): The allowed commandCode. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyCommandCode TPM Command: TPM2_PolicyCommandCode """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _check_friendly_int(code, "code", TPM2_CC) _chkrc( lib.Esys_PolicyCommandCode( self._ctx, policy_session, session1, session2, session3, code ) ) def policy_physical_presence( self, policy_session: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyPhysicalPresence command. This function invokes the TPM2_PolicyPhysicalPresence command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyPhysicalPresence TPM Command: TPM2_PolicyPhysicalPresence """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyPhysicalPresence( self._ctx, policy_session, session1, session2, session3 ) ) def policy_cp_hash( self, policy_session: ESYS_TR, cp_hash_a: Union[TPM2B_DIGEST, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyCpHash command. This function invokes the TPM2_PolicyCpHash command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): The cpHash added to the policy. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyCpHash TPM Command: TPM2_PolicyCpHash """ _check_handle_type(policy_session, "policy_session") cp_hash_a_cdata = _get_cdata(cp_hash_a, TPM2B_DIGEST, "cp_hash_a") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyCpHash( self._ctx, policy_session, session1, session2, session3, cp_hash_a_cdata ) ) def policy_name_hash( self, policy_session: ESYS_TR, name_hash: Union[TPM2B_DIGEST, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyNameHash command. This function invokes the TPM2_PolicyNameHash command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. name_hash (Union[TPM2B_DIGEST, bytes, str]): The digest to be added to the policy. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyNameHash TPM Command: TPM2_PolicyNameHash """ _check_handle_type(policy_session, "policy_session") name_hash_cdata = _get_cdata(name_hash, TPM2B_DIGEST, "name_hash") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyNameHash( self._ctx, policy_session, session1, session2, session3, name_hash_cdata ) ) def policy_duplication_select( self, policy_session: ESYS_TR, object_name: Union[TPM2B_NAME, bytes, str], new_parent_name: Union[TPM2B_NAME, bytes, str], include_object: bool = False, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyDuplicationSelect command. This function invokes the TPM2_PolicyDuplicationSelect command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. object_name (Union[TPM2B_NAME, bytes, str]): The Name of the object to be duplicated. new_parent_name (Union[TPM2B_NAME, bytes, str]): The Name of the new parent. include_object (bool): If YES, the objectName will be included in the value in policySession->policyDigest, optional. Defaults to False. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyDuplicationSelect TPM Command: TPM2_PolicyDuplicationSelect """ _check_handle_type(policy_session, "policy_session") object_name_cdata = _get_cdata(object_name, TPM2B_NAME, "object_name") new_parent_name_cdata = _get_cdata( new_parent_name, TPM2B_NAME, "new_parent_name" ) if not isinstance(include_object, bool): raise TypeError( f"Expected include_object to be type bool, got {type(include_object)}" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyDuplicationSelect( self._ctx, policy_session, session1, session2, session3, object_name_cdata, new_parent_name_cdata, include_object, ) ) def policy_authorize( self, policy_session: ESYS_TR, approved_policy: Union[TPM2B_DIGEST, bytes, str], key_sign: Union[TPM2B_NAME, bytes, str], check_ticket: TPMT_TK_VERIFIED, policy_ref: Union[TPM2B_NONCE, bytes, str] = TPM2B_NONCE(), session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyAuthorize command. This function invokes the TPM2_PolicyAuthorize command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. approved_policy (Union[TPM2B_DIGEST, bytes, str]): Digest of the policy being approved. key_sign (Union[TPM2B_NAME, bytes, str]): Name of a key that can sign a policy addition. check_ticket (TPMT_TK_VERIFIED): Ticket validating that approvedPolicy and policyRef were signed by keySign. policy_ref (Union[TPM2B_NONCE, bytes, str]): A policy qualifier (optional). Defaults to an empty buffer. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyAuthorize TPM Command: TPM2_PolicyAuthorize """ _check_handle_type(policy_session, "policy_session") approved_policy_cdata = _get_cdata( approved_policy, TPM2B_DIGEST, "approved_policy" ) policy_ref_cdata = _get_cdata(policy_ref, TPM2B_NONCE, "policy_ref") key_sign_cdata = _get_cdata(key_sign, TPM2B_NAME, "key_sign") check_ticket_cdata = _get_cdata(check_ticket, TPMT_TK_VERIFIED, "check_ticket") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyAuthorize( self._ctx, policy_session, session1, session2, session3, approved_policy_cdata, policy_ref_cdata, key_sign_cdata, check_ticket_cdata, ) ) def policy_auth_value( self, policy_session: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyAuthValue command. This function invokes the TPM2_PolicyAuthValue command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyAuthValue TPM Command: TPM2_PolicyAuthValue """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyAuthValue( self._ctx, policy_session, session1, session2, session3 ) ) def policy_password( self, policy_session: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyPassword command. This function invokes the TPM2_PolicyPassword command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyPassword TPM Command: TPM2_PolicyPassword """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyPassword( self._ctx, policy_session, session1, session2, session3 ) ) def policy_get_digest( self, policy_session: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DIGEST: """Invoke the TPM2_PolicyGetDigest command. This function invokes the TPM2_PolicyGetDigest command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: The current value of the policySession->policyDigest as a TPM2B_DIGEST. C Function: Esys_PolicyGetDigest TPM Command: TPM2_PolicyGetDigest """ _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") policy_digest = ffi.new("TPM2B_DIGEST **") _chkrc( lib.Esys_PolicyGetDigest( self._ctx, policy_session, session1, session2, session3, policy_digest ) ) return TPM2B_DIGEST(_get_dptr(policy_digest, lib.Esys_Free)) def policy_nv_written( self, policy_session: ESYS_TR, written_set: bool = True, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyNvWritten command. This function invokes the TPM2_PolicyNvWritten command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. written_set (bool): True if NV Index is required to have been written, False otherwise. Defaults to True. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyNvWritten TPM Command: TPM2_PolicyNvWritten """ _check_handle_type(policy_session, "policy_session") if not isinstance(written_set, bool): raise TypeError( f"Expected written_set to be type bool, got {type(written_set)}" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyNvWritten( self._ctx, policy_session, session1, session2, session3, written_set ) ) def policy_template( self, policy_session: ESYS_TR, template_hash: Union[TPM2B_DIGEST, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyTemplate command. This function invokes the TPM2_PolicyTemplate command in a one-call variant. This means the function will block until the TPM response is available. Args: policy_session (ESYS_TR): Handle for the policy session being extended. template_hash (Union[TPM2B_DIGEST, bytes, str]): The digest to be added to the policy. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyTemplate TPM Command: TPM2_PolicyTemplate """ _check_handle_type(policy_session, "policy_session") template_hash_cdata = _get_cdata(template_hash, TPM2B_DIGEST, "template_hash") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyTemplate( self._ctx, policy_session, session1, session2, session3, template_hash_cdata, ) ) def policy_authorize_nv( self, nv_index: ESYS_TR, policy_session: ESYS_TR, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PolicyAuthorizeNV command. This function invokes the TPM2_PolicyAuthorizeNV command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index of the area to read. policy_session (ESYS_TR): Handle for the policy session being extended. auth_handle (ESYS_TR): Handle indicating the source of the authorization value. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PolicyAuthorizeNV TPM Command: TPM2_PolicyAuthorizeNV """ if auth_handle is None: auth_handle = nv_index _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(policy_session, "policy_session") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_PolicyAuthorizeNV( self._ctx, auth_handle, nv_index, policy_session, session1, session2, session3, ) ) def create_primary( self, in_sensitive: Optional[TPM2B_SENSITIVE_CREATE], in_public: Union[TPM2B_PUBLIC, str] = "rsa2048", primary_handle: ESYS_TR = ESYS_TR.OWNER, outside_info: Union[TPM2B_DATA, bytes, str] = TPM2B_DATA(), creation_pcr: Union[TPML_PCR_SELECTION, str] = TPML_PCR_SELECTION(), session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[ ESYS_TR, TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION ]: """Invoke the TPM2_CreatePrimary command. This function invokes the TPM2_CreatePrimary command in a one-call variant. This means the function will block until the TPM response is available. Args: in_sensitive (TPM2B_SENSITIVE_CREATE): The sensitive data, see TPM 2.0 Part 1 Sensitive Values. Accepts None for an empty TPM2B_SENSITIVE_CREATE. in_public (Union[TPM2B_PUBLIC, str]): The public template. Defaults to "rsa2048". primary_handle (ESYS_TR): ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM or ESYS_TR.NULL. Defaults to ESYS_TR.OWNER. outside_info (Union[TPM2B_DATA, bytes, str]): Data that will be included in the creation data for this object to provide permanent, verifiable linkage between this object and some object owner data. Defaults to an empty TPM2B_DATA. creation_pcr (Union[TPML_PCR_SELECTION, str]): PCR that will be used in creation data. Defaults to an empty TPML_PCR_SELECTION(). session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[ESYS_TR, TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION] which is the ESYS_TR handle of ESYS resource for TPM2_HANDLE, the public portion of the created object, the creation data and digest of creation data using the nameAlg of of the object respectively. C Function: Esys_CreatePrimary TPM Command: TPM2_CreatePrimary """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") in_public_cdata = _get_cdata( in_public, TPM2B_PUBLIC, "in_public", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) if in_sensitive is None: in_sensitive = TPM2B_SENSITIVE_CREATE() in_sensitive_cdata = _get_cdata( in_sensitive, TPM2B_SENSITIVE_CREATE, "in_sensitive" ) outside_info_cdata = _get_cdata(outside_info, TPM2B_DATA, "outside_info") creation_pCR_cdata = _get_cdata( creation_pcr, TPML_PCR_SELECTION, "creation_pcr" ) object_handle = ffi.new("ESYS_TR *") out_public = ffi.new("TPM2B_PUBLIC **") creation_data = ffi.new("TPM2B_CREATION_DATA **") creation_hash = ffi.new("TPM2B_DIGEST **") creation_ticket = ffi.new("TPMT_TK_CREATION **") _chkrc( lib.Esys_CreatePrimary( self._ctx, primary_handle, session1, session2, session3, in_sensitive_cdata, in_public_cdata, outside_info_cdata, creation_pCR_cdata, object_handle, out_public, creation_data, creation_hash, creation_ticket, ) ) return ( ESYS_TR(object_handle[0], ectx=self), TPM2B_PUBLIC(_cdata=_get_dptr(out_public, lib.Esys_Free)), TPM2B_CREATION_DATA(_cdata=_get_dptr(creation_data, lib.Esys_Free)), TPM2B_DIGEST(_cdata=_get_dptr(creation_hash, lib.Esys_Free)), TPMT_TK_CREATION(_cdata=_get_dptr(creation_ticket, lib.Esys_Free)), ) def hierarchy_control( self, auth_handle: ESYS_TR, enable: ESYS_TR, state: bool, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_HierarchyControl command. This function invokes the TPM2_HierarchyControl command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER or ESYS_TR.PLATFORM. enable (ESYS_TR): The enable being modified. state (bool): True if the enable should be SET, False if the enable should be CLEAR. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_HierarchyControl TPM Command: TPM2_HierarchyControl """ _check_handle_type( auth_handle, "auth_handle", expected=(ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM), ) _check_handle_type( enable, "enable", expected=(ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM), ) enable = ESAPI._fixup_hierarchy(enable) if not isinstance(state, bool): raise TypeError(f"Expected state to be a bool, got {type(state)}") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_HierarchyControl( self._ctx, auth_handle, session1, session2, session3, enable, state ) ) def set_primary_policy( self, auth_handle: ESYS_TR, auth_policy: Union[TPM2B_DIGEST, bytes, str], hash_alg: TPM2_ALG, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_SetPrimaryPolicy command. This function invokes the TPM2_SetPrimaryPolicy command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER or ESYS_TR.PLATFORM. auth_policy (Union[TPM2B_DIGEST, bytes, str]): authPolicy An authorization policy digest; may be the empty buffer. hash_alg (TPM2_ALG): The hash algorithm to use for the policy. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_SetPrimaryPolicy TPM Command: TPM2_SetPrimaryPolicy """ _check_handle_type( auth_handle, "auth_handle", expected=(ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM), ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") auth_policy_cdata = _get_cdata(auth_policy, TPM2B_DIGEST, "auth_policy") _check_friendly_int(hash_alg, "hash_alg", TPM2_ALG) _chkrc( lib.Esys_SetPrimaryPolicy( self._ctx, auth_handle, session1, session2, session3, auth_policy_cdata, hash_alg, ) ) def change_pps( self, auth_handle: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_ChangePPS command. This function invokes the TPM2_ChangePPS command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ChangePPS TPM Command: TPM2_ChangePPS """ _check_handle_type(auth_handle, "auth_handle", expected=(ESYS_TR.PLATFORM,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc(lib.Esys_ChangePPS(self._ctx, auth_handle, session1, session2, session3)) def change_eps( self, auth_handle: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_ChangeEPS command. This function invokes the TPM2_ChangeEPS command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ChangeEPS TPM Command: TPM2_ChangeEPS """ _check_handle_type(auth_handle, "auth_handle", expected=(ESYS_TR.PLATFORM,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc(lib.Esys_ChangeEPS(self._ctx, auth_handle, session1, session2, session3)) def clear( self, auth_handle: ESYS_TR, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_Clear command. This function invokes the TPM2_Clear command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.LOCKOUT or ESYS_TR.PLATFORM+{PP}. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_Clear TPM Command: TPM2_Clear """ _check_handle_type( auth_handle, "auth_handle", expected=(ESYS_TR.PLATFORM, ESYS_TR.LOCKOUT) ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc(lib.Esys_Clear(self._ctx, auth_handle, session1, session2, session3)) def clear_control( self, auth: ESYS_TR, disable: bool, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_ClearControl command. This function invokes the TPM2_ClearControl command in a one-call variant. This means the function will block until the TPM response is available. Args: auth (ESYS_TR): ESYS_TR.LOCKOUT or ESYS_TR.PLATFORM+{PP}. disable (bool): True if the disableOwnerClear flag is to be SET, False if the flag is to be CLEAR. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ClearControl TPM Command: TPM2_ClearControl """ _check_handle_type(auth, "auth", expected=(ESYS_TR.PLATFORM, ESYS_TR.LOCKOUT)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") if not isinstance(disable, bool): raise TypeError(f"Expected disable to be a bool, got {type(disable)}") _chkrc( lib.Esys_ClearControl( self._ctx, auth, session1, session2, session3, disable ) ) def hierarchy_change_auth( self, auth_handle: ESYS_TR, new_auth: Union[TPM2B_AUTH, bytes, str], session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_HierarchyChangeAuth command. This function invokes the TPM2_HierarchyChangeAuth command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): ESYS_TR.LOCKOUT, ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. new_auth (Union[TPM2B_AUTH, bytes, str]): New authorization value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_HierarchyChangeAuth TPM Command: TPM2_HierarchyChangeAuth """ _check_handle_type( auth_handle, "auth_handle", expected=( ESYS_TR.LOCKOUT, ESYS_TR.ENDORSEMENT, ESYS_TR.OWNER, ESYS_TR.PLATFORM, ), ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") new_auth_cdata = _get_cdata(new_auth, TPM2B_AUTH, "new_auth") _chkrc( lib.Esys_HierarchyChangeAuth( self._ctx, auth_handle, session1, session2, session3, new_auth_cdata ) ) def dictionary_attack_lock_reset( self, lock_handle: ESYS_TR = ESYS_TR.LOCKOUT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_DictionaryAttackLockReset command. This function invokes the TPM2_DictionaryAttackLockReset command in a one-call variant. This means the function will block until the TPM response is available. Args: lock_handle (ESYS_TR): ESYS_TR.LOCKOUT. Defaults to ESYS_TR.LOCKOUT. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_DictionaryAttackLockReset TPM Command: TPM2_DictionaryAttackLockReset """ _check_handle_type(lock_handle, "lock_handle", expected=(ESYS_TR.LOCKOUT,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_DictionaryAttackLockReset( self._ctx, lock_handle, session1, session2, session3 ) ) def dictionary_attack_parameters( self, new_max_tries: int, new_recovery_time: int, lockout_recovery: int, lock_handle: ESYS_TR = ESYS_TR.LOCKOUT, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_DictionaryAttackParameters command. This function invokes the TPM2_DictionaryAttackParameters command in a one-call variant. This means the function will block until the TPM response is available. Args: new_max_tries (int): Count of authorization failures before the lockout is imposed. new_recovery_time (int): Time in seconds before the authorization failure count is automatically decremented. lockout_recovery (int): Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed. lock_handle (ESYS_TR): ESYS_TR.LOCKOUT. Defaults to ESYS_TR.LOCKOUT. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_DictionaryAttackParameters TPM Command: TPM2_DictionaryAttackParameters """ if not isinstance(new_max_tries, int): raise TypeError( f"Expected new_max_tries to be an int, got {type(new_max_tries)}" ) if not isinstance(new_recovery_time, int): raise TypeError( f"Expected new_recovery_time to be an int, got {type(new_recovery_time)}" ) if not isinstance(lockout_recovery, int): raise TypeError( f"Expected lockout_recovery to be an int, got {type(lockout_recovery)}" ) _check_handle_type(lock_handle, "lock_handle", expected=(ESYS_TR.LOCKOUT,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_DictionaryAttackParameters( self._ctx, lock_handle, session1, session2, session3, new_max_tries, new_recovery_time, lockout_recovery, ) ) def pp_commands( self, set_list: TPML_CC, clear_list: TPML_CC, auth: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_PP_Commands command. This function invokes the TPM2_PP_Commands command in a one-call variant. This means the function will block until the TPM response is available. Args: set_list (TPML_CC): List of commands to be added to those that will require that Physical Presence be asserted. clear_list (TPML_CC): clearList List of commands that will no longer require that Physical Presence be asserted. auth (ESYS_TR): ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_PP_Commands TPM Command: TPM2_PP_Commands """ _check_handle_type(auth, "auth", expected=(ESYS_TR.PLATFORM,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") set_list_cdata = _get_cdata(set_list, TPML_CC, "set_list") clear_list_cdata = _get_cdata(clear_list, TPML_CC, "clear_list") _chkrc( lib.Esys_PP_Commands( self._ctx, auth, session1, session2, session3, set_list_cdata, clear_list_cdata, ) ) def set_algorithm_set( self, algorithm_set: Union[List[int], int], auth_handle: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_SetAlgorithmSet command. This function invokes the TPM2_SetAlgorithmSet command in a one-call variant. This means the function will block until the TPM response is available. Args: algorithm_set (Union[List[int], int]): A TPM vendor-dependent value indicating the algorithm set selection. auth_handle (ESYS_TR): ESYS_TR.PLATFORM. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_SetAlgorithmSet TPM Command: TPM2_SetAlgorithmSet """ _check_handle_type(auth_handle, "auth_handle", expected=(ESYS_TR.PLATFORM,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_SetAlgorithmSet( self._ctx, auth_handle, session1, session2, session3, algorithm_set ) ) def field_upgrade_start( self, key_handle: ESYS_TR, fu_digest: Union[TPM2B_DIGEST, bytes, str], manifest_signature: TPMT_SIGNATURE, authorization: ESYS_TR = ESYS_TR.PLATFORM, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_FieldUpgradeStart command. This function invokes the TPM2_FieldUpgradeStart command in a one-call variant. This means the function will block until the TPM response is available. Args: key_handle (ESYS_TR): Handle of a public area that contains the TPM Vendor Authorization Key that will be used to validate manifestSignature. fu_digest (Union[TPM2B_DIGEST, bytes, str]): Digest of the first block in the field upgrade sequence. manifest_signature (TPMT_SIGNATURE): Signature over fuDigest using the key associated with keyHandle (not optional). authorization (ESYS_TR): ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_FieldUpgradeStart TPM Command: TPM2_FieldUpgradeStart """ _check_handle_type(authorization, "authorization") _check_handle_type(key_handle, "key_handle") fu_digest_cdata = _get_cdata(fu_digest, TPM2B_DIGEST, "fu_digest") manifest_signature_cdata = _get_cdata( manifest_signature, TPMT_SIGNATURE, "manifest_signature" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_FieldUpgradeStart( self._ctx, authorization, key_handle, session1, session2, session3, fu_digest_cdata, manifest_signature_cdata, ) ) def field_upgrade_data( self, fu_data: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPMT_HA, TPMT_HA]: """Invoke the TPM2_FieldUpgradeData command. This function invokes the TPM2_FieldUpgradeData command in a one-call variant. This means the function will block until the TPM response is available. Args: fu_data (Union[TPM2B_MAX_BUFFER, bytes, str]): Field upgrade image data. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPMT_HA, TPMT_HA] which is the tagged digest of the next block and the tagged digest of the first block of the sequence respectively. C Function: Esys_FieldUpgradeData TPM Command: TPM2_FieldUpgradeData """ fu_data_cdata = _get_cdata(fu_data, TPM2B_MAX_BUFFER, "fu_data") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") next_digest = ffi.new("TPMT_HA **") first_digest = ffi.new("TPMT_HA **") _chkrc( lib.Esys_FieldUpgradeData( self._ctx, session1, session2, session3, fu_data_cdata, next_digest, first_digest, ) ) return ( TPMT_HA(_get_dptr(next_digest, lib.Esys_Free)), TPMT_HA(_get_dptr(first_digest, lib.Esys_Free)), ) def firmware_read( self, sequence_number: int, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_MAX_BUFFER: """Invoke the TPM2_FirmwareRead command. This function invokes the TPM2_FirmwareRead command in a one-call variant. This means the function will block until the TPM response is available. Args: sequence_number (int): sequenceNumber The number of previous calls to this command in this sequence. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_MAX_BUFFER which is the field upgrade image data. C Function: Esys_FirmwareRead TPM Command: TPM2_FirmwareRead """ if not isinstance(sequence_number, int): raise TypeError( f"Expected sequence_number to be an int, got {type(sequence_number)}" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") fu_data = ffi.new("TPM2B_MAX_BUFFER **") _chkrc( lib.Esys_FirmwareRead( self._ctx, session1, session2, session3, sequence_number, fu_data ) ) return TPM2B_MAX_BUFFER(_get_dptr(fu_data, lib.Esys_Free)) def context_save(self, save_handle: ESYS_TR) -> TPMS_CONTEXT: """Invoke the TPM2_ContextSave command. This function invokes the TPM2_ContextSave command in a one-call variant. This means the function will block until the TPM response is available. Args: save_handle (ESYS_TR): Handle of the resource to save. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMS_CONTEXT which is the saved save_handle data. C Function: Esys_ContextSave TPM Command: TPM2_ContextSave """ _check_handle_type(save_handle, "save_handle") context = ffi.new("TPMS_CONTEXT **") _chkrc(lib.Esys_ContextSave(self._ctx, save_handle, context)) return TPMS_CONTEXT(_get_dptr(context, lib.Esys_Free)) def context_load(self, context: TPMS_CONTEXT) -> ESYS_TR: """Invoke the TPM2_ContextLoad command. This function invokes the TPM2_ContextLoad command in a one-call variant. This means the function will block until the TPM response is available. Args: context (TPMS_CONTEXT): The context blob. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR which is the handle to the loaded data. C Function: Esys_ContextLoad TPM Command: TPM2_ContextLoad """ context_cdata = _get_cdata(context, TPMS_CONTEXT, "context") loaded_handle = ffi.new("ESYS_TR *") _chkrc(lib.Esys_ContextLoad(self._ctx, context_cdata, loaded_handle)) return ESYS_TR(loaded_handle[0], ectx=self) def flush_context(self, flush_handle: ESYS_TR) -> None: """Invoke the TPM2_FlushContext command. This function invokes the TPM2_FlushContext command in a one-call variant. This means the function will block until the TPM response is available. Args: flush_handle (ESYS_TR): The handle of the item to flush. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_FlushContext TPM Command: TPM2_FlushContext """ _check_handle_type(flush_handle, "flush_handle") _chkrc(lib.Esys_FlushContext(self._ctx, flush_handle)) def evict_control( self, auth: ESYS_TR, object_handle: ESYS_TR, persistent_handle: int, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_EvictControl command. This function invokes the TPM2_EvictControl command in a one-call variant. This means the function will block until the TPM response is available. Args: auth (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. object_handle (ESYS_TR): The handle of a loaded object. persistent_handle (int): If objectHandle is a transient object handle, then this is the persistent handle for the object. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR handle of ESYS resource for TPM2_HANDLE. C Function: Esys_EvictControl TPM Command: TPM2_EvictControl """ _check_handle_type(auth, "auth", expected=(ESYS_TR.OWNER, ESYS_TR.PLATFORM)) _check_handle_type(object_handle, "object_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") new_object_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_EvictControl( self._ctx, auth, object_handle, session1, session2, session3, persistent_handle, new_object_handle, ) ) return ESYS_TR(new_object_handle[0]) def read_clock( self, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPMS_TIME_INFO: """Invoke the TPM2_ReadClock command. This function invokes the TPM2_ReadClock command in a one-call variant. This means the function will block until the TPM response is available. Args: session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: The current time as a TPMS_TIME_INFO. C Function: Esys_ReadClock TPM Command: TPM2_ReadClock """ _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") current_time = ffi.new("TPMS_TIME_INFO **") _chkrc( lib.Esys_ReadClock(self._ctx, session1, session2, session3, current_time) ) return TPMS_TIME_INFO(_get_dptr(current_time, lib.Esys_Free)) def clock_set( self, new_time: int, auth: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_ClockSet command. This function invokes the TPM2_ClockSet command in a one-call variant. This means the function will block until the TPM response is available. Args: new_time (int): New Clock setting in milliseconds. auth (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.OWNER. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ClockSet TPM Command: TPM2_ClockSet """ _check_handle_type(auth, "auth") if not isinstance(new_time, int): raise TypeError(f"Expected new_time to be an int, got {type(new_time)}") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_ClockSet(self._ctx, auth, session1, session2, session3, new_time) ) def clock_rate_adjust( self, rate_adjust: TPM2_CLOCK, auth: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_ClockRateAdjust command. This function invokes the TPM2_ClockRateAdjust command in a one-call variant. This means the function will block until the TPM response is available. Args: rate_adjust (TPM2_CLOCK): Adjustment to current Clock update rate. auth (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.OWNER. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ClockRateAdjust TPM Command: TPM2_ClockRateAdjust """ _check_handle_type(auth, "auth", expected=(ESYS_TR.OWNER, ESYS_TR.PLATFORM)) _check_friendly_int(rate_adjust, "rate_adjustvarname", TPM2_CLOCK) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_ClockRateAdjust( self._ctx, auth, session1, session2, session3, rate_adjust ) ) def get_capability( self, capability: TPM2_CAP, prop: int, property_count: int = 1, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[bool, TPMS_CAPABILITY_DATA]: """Invoke the TPM2_GetCapability command. This function invokes the TPM2_GetCapability command in a one-call variant. This means the function will block until the TPM response is available. Args: capability (TPM2_CAP): Group selection; determines the format of the response. prop (int): Further definition of information. property_count (int): Number of properties of the indicated type to return. Defaults to 1. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[bool, TPMS_CAPABILITY_DATA] which is the Flag to indicate if there are more values of this type and the capability data respectively. C Function: Esys_GetCapability TPM Command: TPM2_GetCapability """ _check_friendly_int(capability, "capability", TPM2_CAP) if not isinstance(prop, int): raise TypeError(f"Expected prop to be an int, got {type(prop)}") if not isinstance(property_count, int): raise TypeError( f"Expected property_count to be an int, got {type(property_count)}" ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") more_data = ffi.new("TPMI_YES_NO *") capability_data = ffi.new("TPMS_CAPABILITY_DATA **") _chkrc( lib.Esys_GetCapability( self._ctx, session1, session2, session3, capability, prop, property_count, more_data, capability_data, ) ) return ( bool(more_data[0]), TPMS_CAPABILITY_DATA(_get_dptr(capability_data, lib.Esys_Free)), ) def ac_get_capability( self, ac: ESYS_TR, capability: TPM_AT, count: int, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[bool, TPML_AC_CAPABILITIES]: """Invoke the TPM2_AC_GetCapability command. This function invokes the TPM2_AC_GetCapability command in a one-call variant. This means the function will block until the TPM response is available. Args: ac (ESYS_TR): Handle indicating the attached component. capability (TPM_AT): Group selection; determines the format of the response. count (int): Number of properties of the indicated type to return. Defaults to 1. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[bool, TPML_AC_CAPABILITIES] which is the Flag to indicate if there are more values of this type and the capability data respectively. C Function: Esys_AC_GetCapability TPM Command: TPM2_AC_GetCapability """ if not _lib_version_atleast("tss2-esys", "4.0.0"): raise NotImplementedError("MAC api not supported below ESAPI v4") _check_friendly_int(capability, "capability", TPM_AT) if not isinstance(count, int): raise TypeError(f"Expected count to be an int, got {type(prop)}") _check_handle_type(ac, "ac") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") more_data = ffi.new("TPMI_YES_NO *") capability_data = ffi.new("TPML_AC_CAPABILITIES **") _chkrc( lib.Esys_AC_GetCapability( self._ctx, session1, session2, session3, ac, capability, count, more_data, capability_data, ) ) return ( bool(more_data[0]), TPML_AC_CAPABILITIES(_get_dptr(capability_data, lib.Esys_Free)), ) def ac_send( self, ac: ESYS_TR, send_object: ESYS_TR, nv_auth_handle: ESYS_TR, ac_data_in: Union[TPM2B_MAX_BUFFER, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPMS_AC_OUTPUT: """Invoke the TPM2_AC_Send command. This function invokes the TPM2_AC_Send command in a one-call variant. This means the function will block until the TPM response is available. Args: ac (ESYS_TR): Handle indicating the attached component. send_object (ESYS_TR): Handle of the object being sent to ac nv_auth_handle (ESYS_TR): Handle indicating the source of the authorization value ac_data_in (Union[TPM2B_MAX_BUFFER, bytes, str]): Optional non sensitive information related to the object session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMS_AC_OUTPUT result, may include AC specific data or information about an error. C Function: Esys_AC_Send TPM Command: TPM2_AC_Send """ if not _lib_version_atleast("tss2-esys", "4.0.0"): raise NotImplementedError("MAC api not supported below ESAPI v4") _check_handle_type(ac, "ac") _check_handle_type(send_object, "send_object") _check_handle_type(nv_auth_handle, "nv_auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") buffer_cdata = _get_cdata(ac_data_in, TPM2B_MAX_BUFFER, "ac_data_in") ac_data_out = ffi.new("TPMS_AC_OUTPUT **") _chkrc( lib.Esys_AC_Send( self._ctx, send_object, nv_auth_handle, session1, session2, session3, ac, buffer_cdata, ac_data_out, ) ) return TPMS_AC_OUTPUT(_get_dptr(acDataOut, lib.Esys_Free)) def policy_ac_send_select( self, object_name: Union[TPM2B_NAME, bytes, str], auth_handle_name: Union[TPM2B_NAME, bytes, str], ac_name: Union[TPM2B_NAME, bytes, str], include_object: TPMI_YES_NO, policy_session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_Policy_AC_SendSelect command. This function invokes the TPM2_Policy_AC_SendSelect command in a one-call variant. This means the function will block until the TPM response is available. Args: ac (ESYS_TR): Handle indicating the attached component. object_name (Union[TPM2B_NAME, bytes, str]): Name of the Object to be sent auth_handle_name (Union[TPM2B_NAME, bytes, str]): Name associated with authHandle used in the TPM2_AC_Send() command auth_handle_name (Union[TPM2B_NAME, bytes, str]): Name of the Attached Component to which the Object will be sent include_object (TPMI_YES_NO): If SET, objectName will be included in the value in policySession→policyDigest policy_session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPMS_AC_OUTPUT result, may include AC specific data or information about an error. C Function: Esys_Policy_AC_SendSelect TPM Command: TPM2_Policy_AC_SendSelect """ if not _lib_version_atleast("tss2-esys", "4.0.0"): raise NotImplementedError("MAC api not supported below ESAPI v4") object_name_cdata = _get_cdata(object_name, TPM2B_NAME, "object_name") auth_handle_name_cdata = _get_cdata( auth_handle_name, TPM2B_NAME, "auth_handle_name" ) ac_name_cdata = _get_cdata(ac_name, TPM2B_NAME, "ac_name") _check_handle_type(policy_session1, "policy_session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_Policy_AC_SendSelect( self._ctx, policy_session1, session2, session3, object_name_cdata, auth_handle_name_cdata, ac_name_cdata, include_object, ) ) def test_parms( self, parameters: TPMT_PUBLIC_PARMS, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_TestParms command. This function invokes the TPM2_TestParms command in a one-call variant. This means the function will block until the TPM response is available. Args: parameters (TPMT_PUBLIC_PARMS): Algorithm parameters to be validated. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_TestParms TPM Command: TPM2_TestParms """ parameters_cdata = _get_cdata(parameters, TPMT_PUBLIC_PARMS, "parameters") _chkrc( lib.Esys_TestParms( self._ctx, session1, session2, session3, parameters_cdata ) ) def nv_define_space( self, auth: Union[TPM2B_AUTH, bytes, str, None], public_info: TPM2B_NV_PUBLIC, auth_handle: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> ESYS_TR: """Invoke the TPM2_NV_DefineSpace command. This function invokes the TPM2_NV_DefineSpace command in a one-call variant. This means the function will block until the TPM response is available. Args: auth (Union[TPM2B_AUTH, bytes, str, None]): The authorization value. public_info (TPM2B_NV_PUBLIC): The public parameters of the NV area. auth_handle (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.OWNER. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: An ESYS_TR handle of ESYS resource for TPM2_HANDLE. C Function: Esys_NV_DefineSpace TPM Command: TPM2_NV_DefineSpace """ _check_handle_type( auth_handle, "auth_handle", expected=(ESYS_TR.OWNER, ESYS_TR.PLATFORM) ) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") auth_cdata = _get_cdata(auth, TPM2B_AUTH, "auth", allow_none=True) public_info_cdata = _get_cdata(public_info, TPM2B_NV_PUBLIC, "public_info") nv_handle = ffi.new("ESYS_TR *") _chkrc( lib.Esys_NV_DefineSpace( self._ctx, auth_handle, session1, session2, session3, auth_cdata, public_info_cdata, nv_handle, ) ) return ESYS_TR(nv_handle[0]) def nv_undefine_space( self, nv_index: ESYS_TR, auth_handle: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_UndefineSpace command. This function invokes the TPM2_NV_UndefineSpace command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): he NV Index to remove from NV space. auth_handle (ESYS_TR): ESYS_TR.OWNER or ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.OWNER. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_UndefineSpace TPM Command: TPM2_NV_UndefineSpace """ _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_UndefineSpace( self._ctx, auth_handle, nv_index, session1, session2, session3 ) ) def nv_undefine_space_special( self, nv_index: ESYS_TR, session1: ESYS_TR, platform: ESYS_TR = ESYS_TR.PLATFORM, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_UndefineSpaceSpecial command. This function invokes the TPM2_NV_UndefineSpaceSpecial command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): Index to be deleted. session1 (ESYS_TR): Session handle for authorization of nvIndex (required). platform (ESYS_TR): platform ESYS_TR.PLATFORM+{PP}. Defaults to ESYS_TR.PLATFORM. session2 (ESYS_TR): Session handle for authorization of platform (optional). Defaults to ESYS_TR.PASSWORD. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_UndefineSpaceSpecial TPM Command: TPM2_NV_UndefineSpaceSpecial """ _check_handle_type(nv_index, "nv_index") _check_handle_type(platform, "platform", expected=(ESYS_TR.PLATFORM,)) _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_UndefineSpaceSpecial( self._ctx, nv_index, platform, session1, session2, session3 ) ) def nv_read_public( self, nv_index: ESYS_TR, session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_NV_PUBLIC, TPM2B_NAME]: """Invoke the TPM2_NV_ReadPublic command. This function invokes the TPM2_NV_ReadPublic command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_NV_PUBLIC, TPM2B_NAME] which is the public area of the NV Index and the name of the NV Index respectively. C Function: Esys_NV_ReadPublic TPM Command: TPM2_NV_ReadPublic """ _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") nv_public = ffi.new("TPM2B_NV_PUBLIC **") nv_name = ffi.new("TPM2B_NAME **") _chkrc( lib.Esys_NV_ReadPublic( self._ctx, nv_index, session1, session2, session3, nv_public, nv_name ) ) return ( TPM2B_NV_PUBLIC(_cdata=_get_dptr(nv_public, lib.Esys_Free)), TPM2B_NAME(_cdata=_get_dptr(nv_name, lib.Esys_Free)), ) def nv_write( self, nv_index: ESYS_TR, data: Union[TPM2B_MAX_NV_BUFFER, bytes, str], offset: int = 0, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_Write command. This function invokes the TPM2_NV_Write command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index of the area to write. data (Union[TPM2B_MAX_NV_BUFFER, bytes, str]): The data to write. offset (int): The offset into the NV Area. Defaults to 0. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_Write TPM Command: TPM2_NV_Write """ if auth_handle is None: auth_handle = nv_index _check_handle_type(nv_index, "nv_index") _check_handle_type(auth_handle, "auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") data_cdata = _get_cdata(data, TPM2B_MAX_NV_BUFFER, "data") _chkrc( lib.Esys_NV_Write( self._ctx, auth_handle, nv_index, session1, session2, session3, data_cdata, offset, ) ) def nv_increment( self, nv_index: ESYS_TR, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_Increment command. This function invokes the TPM2_NV_Increment command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to increment. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_Increment TPM Command: TPM2_NV_Increment """ if auth_handle is None: auth_handle = nv_index _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_Increment( self._ctx, auth_handle, nv_index, session1, session2, session3 ) ) def nv_extend( self, nv_index: ESYS_TR, data: Union[TPM2B_MAX_NV_BUFFER, bytes, str], auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_Extend command. This function invokes the TPM2_NV_Extend command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to extend. data (Union[TPM2B_MAX_NV_BUFFER, bytes, str]): The data to extend. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_Extend TPM Command: TPM2_NV_Extend """ if auth_handle is None: auth_handle = nv_index _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") data_cdata = _get_cdata(data, TPM2B_MAX_NV_BUFFER, "data") _chkrc( lib.Esys_NV_Extend( self._ctx, auth_handle, nv_index, session1, session2, session3, data_cdata, ) ) def nv_set_bits( self, nv_index: ESYS_TR, bits: int, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_SetBits command. This function invokes the TPM2_NV_SetBits command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to extend. bits (int): The data to OR with the current contents. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_SetBits TPM Command: TPM2_NV_SetBits """ if auth_handle is None: auth_handle = nv_index _check_handle_type(auth_handle, "auth_handle") if not isinstance(bits, int): raise TypeError(f"Expected bits to be an int, got {type(bits)}") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_SetBits( self._ctx, auth_handle, nv_index, session1, session2, session3, bits ) ) def nv_write_lock( self, nv_index: ESYS_TR, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_WriteLock command. This function invokes the TPM2_NV_WriteLock command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to extend. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_WriteLock TPM Command: TPM2_NV_WriteLock """ if auth_handle is None: auth_handle = nv_index _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_WriteLock( self._ctx, auth_handle, nv_index, session1, session2, session3 ) ) def nv_global_write_lock( self, auth_handle: ESYS_TR = ESYS_TR.OWNER, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_GlobalWriteLock command. This function invokes the TPM2_NV_GlobalWriteLock command in a one-call variant. This means the function will block until the TPM response is available. Args: auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_GlobalWriteLock TPM Command: TPM2_NV_GlobalWriteLock """ _check_handle_type(auth_handle, "auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_GlobalWriteLock( self._ctx, auth_handle, session1, session2, session3 ) ) def nv_read( self, nv_index: ESYS_TR, size: int, offset: int = 0, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_MAX_NV_BUFFER: """Invoke the TPM2_NV_Read command. This function invokes the TPM2_NV_Read command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to be read. size (int): Number of octets to read. offset (int): Octet offset into the area (optional). Defaults to 0. auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_MAX_NV_BUFFER which is the data read. C Function: Esys_NV_Read TPM Command: TPM2_NV_Read """ if auth_handle is None: auth_handle = nv_index _check_handle_type(nv_index, "nv_index") if not isinstance(size, int): raise TypeError(f"Expected size to be an int, got {type(size)}") if not isinstance(offset, int): raise TypeError(f"Expected offset to be an int, got {type(offset)}") _check_handle_type(auth_handle, "auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") data = ffi.new("TPM2B_MAX_NV_BUFFER **") _chkrc( lib.Esys_NV_Read( self._ctx, auth_handle, nv_index, session1, session2, session3, size, offset, data, ) ) return TPM2B_MAX_NV_BUFFER(_get_dptr(data, lib.Esys_Free)) def nv_read_lock( self, nv_index: ESYS_TR, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_ReadLock command. This function invokes the TPM2_NV_ReadLock command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): The NV Index to be locked. auth_handle (ESYS_TR): Handle indicating the source of the authorization (optional). Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_ReadLock TPM Command: TPM2_NV_ReadLock """ if auth_handle is None: auth_handle = nv_index _check_handle_type(nv_index, "nv_index") _check_handle_type(auth_handle, "auth_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_NV_ReadLock( self._ctx, auth_handle, nv_index, session1, session2, session3 ) ) def nv_change_auth( self, nv_index: ESYS_TR, new_auth: Union[TPM2B_DIGEST, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> None: """Invoke the TPM2_NV_ChangeAuth command. This function invokes the TPM2_NV_ChangeAuth command in a one-call variant. This means the function will block until the TPM response is available. Args: nv_index (ESYS_TR): Handle of the entity. new_auth (Union[TPM2B_DIGEST, bytes, str]): New authorization value. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_NV_ChangeAuth TPM Command: TPM2_NV_ChangeAuth """ _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") new_auth_cdata = _get_cdata(new_auth, TPM2B_DIGEST, "new_auth") _chkrc( lib.Esys_NV_ChangeAuth( self._ctx, nv_index, session1, session2, session3, new_auth_cdata ) ) def nv_certify( self, sign_handle: ESYS_TR, nv_index: ESYS_TR, qualifying_data: Union[TPM2B_DATA, bytes, str], in_scheme: TPMT_SIG_SCHEME, size: int, offset: int = 0, auth_handle: Optional[ESYS_TR] = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.PASSWORD, session3: ESYS_TR = ESYS_TR.NONE, ) -> Tuple[TPM2B_ATTEST, TPMT_SIGNATURE]: """Invoke the TPM2_NV_Certify command. This function invokes the TPM2_NV_Certify command in a one-call variant. This means the function will block until the TPM response is available. Args: sign_handle (ESYS_TR): Handle of the key used to sign the attestation structure. nv_index (ESYS_TR): Index for the area to be certified. qualifying_data (Union[TPM2B_DATA, bytes, str]): User-provided qualifying data. in_scheme (TPMT_SIG_SCHEME): TPM2_Signing scheme to use if the scheme for signHandle is TPM2_ALG.NULL. size (int): Number of octets to certify. offset (int): Octet offset into the area (optional). Defaults to 0. auth_handle (ESYS_TR): Handle indicating the source of the authorization (optional). Defaults to the nv_index. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A Tuple[TPM2B_ATTEST, TPMT_SIGNATURE] which is the structure that was signed and the signature over that structure respectively. C Function: Esys_NV_Certify TPM Command: TPM2_NV_Certify """ if auth_handle is None: auth_handle = nv_index _check_handle_type(sign_handle, "sign_handle") _check_handle_type(auth_handle, "auth_handle") _check_handle_type(nv_index, "nv_index") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") qualifying_data_cdata = _get_cdata( qualifying_data, TPM2B_DATA, "qualifying_data" ) in_scheme_cdata = _get_cdata(in_scheme, TPMT_SIG_SCHEME, "in_scheme") if not isinstance(size, int): raise TypeError(f"Expected size to be of type int, got: {type(size)}") if not isinstance(offset, int): raise TypeError(f"Expected offset to be of type int, got: {type(offset)}") certify_info = ffi.new("TPM2B_ATTEST **") signature = ffi.new("TPMT_SIGNATURE **") _chkrc( lib.Esys_NV_Certify( self._ctx, sign_handle, auth_handle, nv_index, session1, session2, session3, qualifying_data_cdata, in_scheme_cdata, size, offset, certify_info, signature, ) ) return ( TPM2B_ATTEST(_get_dptr(certify_info, lib.Esys_Free)), TPMT_SIGNATURE(_get_dptr(signature, lib.Esys_Free)), ) def act_set_timeout( self, act_handle: ESYS_TR, start_timeout: int, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ): """Invoke the TPM2_ACT_SetTimeout command. This function invokes the TPM2_ACT_SetTimeout command in a one-call variant. This means the function will block until the TPM response is available. Args: act_handle (ESYS_TR): ACT handle to set the timeout on. start_timeout (int): The start timeout value for the ACT in seconds. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. C Function: Esys_ACT_SetTimeout TPM Command: TPM2_ACT_SetTimeout """ if not _lib_version_atleast("tss2-esys", "3.1.0"): raise NotImplementedError( "act_set_timeout requires tss2-esys 3.1.0 or higher" ) _check_handle_type(act_handle, "act_handle") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") _chkrc( lib.Esys_ACT_SetTimeout( self._ctx, act_handle, session1, session2, session3, start_timeout ) ) def vendor_tcg_test( self, input_data: Union[TPM2B_DATA, bytes, str], session1: ESYS_TR = ESYS_TR.NONE, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ) -> TPM2B_DATA: """Invoke the TPM2_Vendor_TCG_Test command. This function invokes the TPM2_Vendor_TCG_Test command in a one-call variant. This means the function will block until the TPM response is available. Args: input_data (Union[TPM2B_DATA, bytes, str]): Dummy data. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. Raises: TypeError: If a parameter is not of an expected type. ValueError: If a parameter is not of an expected value. TSS2_Exception: Any of the various TSS2_RC's the lower layers can return. Returns: A TPM2B_DATA which is the output dummy data. C Function: Esys_Vendor_TCG_Test TPM Command: TPM2_Vendor_TCG_Test """ input_data_cdata = _get_cdata(input_data, TPM2B_DATA, "input_data") _check_handle_type(session1, "session1") _check_handle_type(session2, "session2") _check_handle_type(session3, "session3") output_data = ffi.new("TPM2B_DATA **") _chkrc( lib.Esys_Vendor_TCG_Test( self._ctx, session1, session2, session3, input_data_cdata, output_data ) ) return TPM2B_DATA(_get_dptr(output_data, lib.Esys_Free)) def load_blob( self, data: bytes, type_: int = _DEFAULT_LOAD_BLOB_SELECTOR ) -> ESYS_TR: """load binary ESAPI object as binary blob. Supported are the types :const:`constants.FAPI_ESYSBLOB.CONTEXTLOAD` and :const:`constants.FAPI_ESYSBLOB.DESERIALIZE`. Args: data (bytes): Binary blob of the ESAPI object to load. type_ (int): :const:`constants.FAPI_ESYSBLOB.CONTEXTLOAD` or :const:`constants.FAPI_ESYSBLOB.DESERIALIZE`. Defaults to :const:`constants.FAPI_ESYSBLOB.CONTEXTLOAD` if FAPI is installed else :const:`constants.FAPI_ESYSBLOB.DESERIALIZE`. Raises: ValueError: If type\\_ is not of an expected value. Returns: ESYS_TR: The ESAPI handle to the loaded object. """ esys_handle = ffi.new("ESYS_TR *") if type_ == FAPI_ESYSBLOB.CONTEXTLOAD: offs = ffi.new("size_t *", 0) key_ctx = ffi.new("TPMS_CONTEXT *") _chkrc(lib.Tss2_MU_TPMS_CONTEXT_Unmarshal(data, len(data), offs, key_ctx)) _chkrc(lib.Esys_ContextLoad(self._ctx, key_ctx, esys_handle)) elif type_ == FAPI_ESYSBLOB.DESERIALIZE: _chkrc(lib.Esys_TR_Deserialize(self._ctx, data, len(data), esys_handle)) else: raise ValueError( f"Expected type_ to be FAPI_ESYSBLOB.CONTEXTLOAD or FAPI_ESYSBLOB.DESERIALIZE, got {type_}" ) return ESYS_TR(esys_handle[0], ectx=self) def tr_serialize(self, esys_handle: ESYS_TR) -> bytes: """Serialization of an ESYS_TR into a byte buffer. Serialize the metadata of an ESYS_TR object into a byte buffer such that it can be stored on disk for later use by a different program or context. The serialized object can be deserialized using tr_deserialize. Args: esys_handle (ESYS_TR): The ESYS_TR object to serialize. Returns: The serialized object as bytes. C Function: Esys_TR_Serialize Raises: TypeError: If esys_handle is not an ESYS_TR. TSS2_Exception: - TSS2_ESYS_RC_BAD_TR if the ESYS_TR object is unknown to the ESYS_CONTEXT. - TSS2_ESYS_RC_MEMORY if the buffer for marshaling the object can't be allocated. - TSS2_ESYS_RC_BAD_VALUE For invalid ESYS data to be marshaled. - TSS2_RCs produced by lower layers of the software stack. """ _check_handle_type(esys_handle, "esys_handle") buffer_size = ffi.new("size_t *") buffer = ffi.new("uint8_t **") _chkrc(lib.Esys_TR_Serialize(self._ctx, esys_handle, buffer, buffer_size)) buffer_size = buffer_size[0] buffer = _get_dptr(buffer, lib.Esys_Free) return bytes(ffi.buffer(buffer, buffer_size)) def tr_deserialize(self, buffer: bytes) -> ESYS_TR: """Deserialization of an ESYS_TR from a byte buffer. Deserialize the metadata of an ESYS_TR object from a byte buffer that was stored on disk for later use by a different program or context. An object can be serialized using tr_serialize. Args: buffer (bytes): The ESYS_TR object to deserialize. Returns: ESYS_TR: The ESAPI handle to the deserialized object. C Function: Esys_TR_Deserialize Raises: TypeError: If a parameter is the incorrect type. TSS2_Exception: - TSS2_ESYS_RC_MEMORY if the object can not be allocated. - TSS2_RCs produced by lower layers of the software stack. """ if not isinstance(buffer, bytes): raise TypeError(f"Expected buffer to be of type bytes, got: {type(buffer)}") esys_handle = ffi.new("ESYS_TR *") _chkrc(lib.Esys_TR_Deserialize(self._ctx, buffer, len(buffer), esys_handle)) return ESYS_TR(esys_handle[0], ectx=self) @staticmethod def _fixup_hierarchy(hierarchy: ESYS_TR) -> Union[TPM2_RH, ESYS_TR]: """Fixup ESYS_TR values to TPM2_RH constants to work around tpm2-tss API change in 3.0.0. In versions tpm2-tss version before 3.0.0 the TPM2_RH constants were used Esys_LoadExternal, however the spec and API idioms dictate that an ESYS_TR should be used, and thus that change was made. To keep the API constant always expect ESYS_TR's in the Python code and fix them up under the hood for old ESAPI versions. Args: hierarchy (ESYS_TR): The ESYS_TR object to map tp TPM2_RH constant. Returns: The TPM2_RH. Raises: - ValueError: If a parameter is the incorrect value. """ if not _lib_version_atleast("tss2-esys", "3.0.0"): fixup_map = { ESYS_TR.NULL: TPM2_RH.NULL, ESYS_TR.OWNER: TPM2_RH.OWNER, ESYS_TR.PLATFORM: TPM2_RH.PLATFORM, ESYS_TR.ENDORSEMENT: TPM2_RH.ENDORSEMENT, } if hierarchy not in fixup_map: raise RuntimeError( "Expected hierarchy to be one of ESYS_TR.NULL, ESYS_TR.PLATFORM, ESYS_TR.OWNER, ESYS_TR.ENDORSMENT" ) hierarchy = fixup_map[hierarchy] return hierarchy tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/FAPI.py000066400000000000000000001462741506405471500202670ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .internal.utils import _lib_version_atleast if not _lib_version_atleast("tss2-fapi", "3.0.0"): raise NotImplementedError("FAPI Not installed or version is not 3.0.0") import contextlib import json import logging import os import tempfile from typing import Any, Callable, List, Optional, Tuple, Union from ._libtpm2_pytss import ffi, lib from .fapi_info import FapiInfo from .internal.utils import _chkrc, _check_bug_fixed, _get_dptr, _to_bytes_or_null from .TCTI import TCTI from .types import TPM2B_PUBLIC, TPM2B_PRIVATE from .constants import TSS2_RC, TPM2_ALG from .TSS2_Exception import TSS2_Exception logger = logging.getLogger(__name__) FAPI_CONFIG_ENV = "TSS2_FAPICONF" FAPI_CONFIG_PATHS = [ "/etc/tpm2-tss/fapi-config.json", "/usr/local/etc/tpm2-tss/fapi-config.json", ] _cffi_malloc = ffi.new_allocator(free=None) class FAPIConfig(contextlib.ExitStack): """Context to create a temporary Fapi environment.""" def __init__(self, config: Optional[dict] = None, temp_dirs: bool = True, **kwargs): f"""Create a temporary Fapi environment. Get the fapi_conf in this order: * `config` if given * File specified with environment variable `{FAPI_CONFIG_ENV}` if defined * Installed config at `{FAPI_CONFIG_PATHS}` Single entries are overridden if additional named arguments are given and/or if `temp_dirs` is True. Args: config (dict): Fapi configuration to use instead of the installed `fapi-config.json`. Defaults to None. temp_dirs (bool): Create temporary keystore and log directories and set the respective config entries. Defaults to True. **kwargs: Single configuration entries which override those in `config` or `fapi-config.json`. """ super().__init__() self.config_env_backup = None self.config_tmp_path = None self.config = config # Return if no custom fapi config is used if not (config is not None or temp_dirs or kwargs): return if self.config is None: # Load the currently active fapi-config.json config_path = os.environ.get(FAPI_CONFIG_ENV, None) if config_path is None: for p in FAPI_CONFIG_PATHS: try: with open(p) as file: self.config = json.load(file) break except FileNotFoundError: # keep trying pass if self.config is None: raise RuntimeError( f"Could not find fapi config at {FAPI_CONFIG_PATHS}, " f"set env var {FAPI_CONFIG_ENV}" ) else: with open(config_path) as file: self.config = json.load(file) self.config = {**self.config, **kwargs} if temp_dirs: temp_dir_config = { "user_dir": self.enter_context(tempfile.TemporaryDirectory()), "system_dir": self.enter_context(tempfile.TemporaryDirectory()), "log_dir": self.enter_context(tempfile.TemporaryDirectory()), } conflicting_keys = [k for k in temp_dir_config.keys() if k in kwargs] if conflicting_keys: raise ValueError( f"Conflicting config entries from temp_dirs and **kwargs: {conflicting_keys}" ) self.config = {**self.config, **temp_dir_config} with tempfile.NamedTemporaryFile(mode="w", delete=False) as fapi_conf_file: self.config_tmp_path = fapi_conf_file.name fapi_conf_file.write(json.dumps(self.config)) logger.debug( f"Creating FAPIConfig: {self.config_tmp_path}:\n{json.dumps(self.config, indent=4)}" ) # Set fapi config env variable self.config_env_backup = os.environ.get(FAPI_CONFIG_ENV, None) os.environ[FAPI_CONFIG_ENV] = self.config_tmp_path def __exit__(self, exc_type, exc_val, exc_tb): super().__exit__(exc_type, exc_val, exc_tb) if self.config_env_backup is not None: os.environ[FAPI_CONFIG_ENV] = self.config_env_backup else: del os.environ[FAPI_CONFIG_ENV] if self.config_tmp_path is not None: os.unlink(self.config_tmp_path) class _FAPI_CB_UDATA: def __init__(self, cb, udata): self.cur_exc = None self.udata = udata self.cb = cb @ffi.def_extern() def _fapi_auth_callback(object_path, description, auth, user_data): cb_udata: _FAPI_CB_UDATA = ffi.from_handle(user_data) if not cb_udata.cb: return TSS2_RC.FAPI_RC_NOT_IMPLEMENTED try: got_auth: Optional[bytes, str] = cb_udata.cb( ffi.string(object_path), ffi.string(description), cb_udata.udata ) auth_bytes = got_auth.decode() if isinstance(got_auth, str) else got_auth auth[0] = _cffi_malloc("char[]", auth_bytes) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.FAPI_RC_NOT_IMPLEMENTED cb_udata.cur_exc = e return rc return TSS2_RC.RC_SUCCESS @ffi.def_extern() def _fapi_policy_action_callback(object_path, action, user_data): cb_udata: _FAPI_CB_UDATA = ffi.from_handle(user_data) if not cb_udata.cb: return TSS2_RC.FAPI_RC_NOT_IMPLEMENTED try: cb_udata.cb( ffi.string(object_path).decode(), ffi.string(action).decode(), cb_udata.udata, ) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.FAPI_RC_NOT_IMPLEMENTED cb_udata.cur_exc = e return rc return TSS2_RC.RC_SUCCESS @ffi.def_extern() def _fapi_sign_callback( object_path, description, publickey, publickey_hint, hashalg, data_to_sign, data_to_sign_size, signature, signature_size, user_data, ): cb_udata: _FAPI_CB_UDATA = ffi.from_handle(user_data) if not cb_udata.cb: return TSS2_RC.FAPI_RC_NOT_IMPLEMENTED try: sig: bytes = cb_udata.cb( ffi.string(object_path).decode(), ffi.string(description).decode(), ffi.string(publickey).decode(), ffi.string(publickey_hint).decode(), TPM2_ALG(hashalg), ffi.buffer(data_to_sign, data_to_sign_size)[:], cb_udata.udata, ) signature_size[0] = len(sig) signature[0] = _cffi_malloc("char[]", sig) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.FAPI_RC_GENERAL_FAILURE cb_udata.cur_exc = e return rc return TSS2_RC.RC_SUCCESS @ffi.def_extern() def _fapi_branch_callback( object_path, description, branch_names, num_branches, selected_branch, user_data ): cb_udata: _FAPI_CB_UDATA = ffi.from_handle(user_data) if not cb_udata.cb: return TSS2_RC.FAPI_RC_NOT_IMPLEMENTED try: branch_list = [ ffi.string(x).decode() for x in ffi.unpack(branch_names, num_branches) ] position: int = cb_udata.cb( ffi.string(object_path).decode(), ffi.string(description).decode(), branch_list, cb_udata.udata, ) selected_branch[0] = position except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.FAPI_RC_NOT_IMPLEMENTED cb_udata.cur_exc = e return rc return TSS2_RC.RC_SUCCESS class FAPI: """The TPM2 Feature API. This class can be used as a python context or be closed manually via :meth:`~tpm2_pytss.FAPI.close`. """ def __init__(self, uri: Optional[Union[bytes, str]] = None): self.encoding = "utf-8" self._ctx_pp = ffi.new("FAPI_CONTEXT **") uri = _to_bytes_or_null(uri) ret = lib.Fapi_Initialize(self._ctx_pp, uri) _chkrc(ret) self._callback_metadata = {} @property def _ctx(self): """Get the Feature API C context used by the library to hold state. Returns: The Feature API C context. """ return self._ctx_pp[0] def __enter__(self): return self def __exit__(self, _type, value, traceback): self.close() def close(self) -> None: """Finalize the Feature API. This frees allocated memory and invalidates the FAPI object.""" lib.Fapi_Finalize(self._ctx_pp) # TODO flesh out info class @property def version(self): """ Get the tpm2-tss library version. Returns: str: The Feature API C context. """ info = json.loads(self.get_info()) return FapiInfo(info).version @property def config(self): # TODO doc, test info = json.loads(self.get_info()) return FapiInfo(info).fapi_config @property def tcti(self): # TODO doc, test tcti = ffi.new("TSS2_TCTI_CONTEXT **") # returns the actual tcti context, not a copy (so no extra memory is allocated by the fapi) ret = lib.Fapi_GetTcti(self._ctx, tcti) _chkrc(ret) return TCTI(tcti[0]) def provision( self, auth_value_eh: Optional[Union[bytes, str]] = None, auth_value_sh: Optional[Union[bytes, str]] = None, auth_value_lockout: Optional[Union[bytes, str]] = None, is_provisioned_ok: bool = True, ) -> bool: """Provision the Feature API. Creates the keystore and creates some TPM objects. See also config file `/etc/tpm2-tss/fapi-config.json`. Args: auth_value_eh (bytes or str): Endorsement Hierarchy password. Defaults to None. auth_value_sh (bytes or str): Storage/Owner Hierarchy password. Defaults to None. auth_value_lockout (bytes or str): Lockout Hierarchy password. Defaults to None. is_provisioned_ok (bool): Do not throw a TSS2_Exception if Fapi is already provisioned. Defaults to True. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bool: True if Fapi was provisioned, False otherwise. """ auth_value_eh = _to_bytes_or_null(auth_value_eh) auth_value_sh = _to_bytes_or_null(auth_value_sh) auth_value_lockout = _to_bytes_or_null(auth_value_lockout, allow_null=False) ret = lib.Fapi_Provision( self._ctx, auth_value_eh, auth_value_sh, auth_value_lockout ) _chkrc( ret, acceptable=( [lib.TSS2_FAPI_RC_ALREADY_PROVISIONED] if is_provisioned_ok else None ), ) return ret == lib.TPM2_RC_SUCCESS def get_random(self, num_bytes: int) -> bytes: """Get true random bytes, generated by the TPM. Args: num_bytes (int): Number of bytes to generate. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The random bytes. """ if num_bytes > 1024: logger.warning( "Requesting a large number of bytes. This may take a while: {num_bytes}" ) data = ffi.new("uint8_t **") ret = lib.Fapi_GetRandom(self._ctx, num_bytes, data) _chkrc(ret) return bytes(ffi.unpack(_get_dptr(data, lib.Fapi_Free), num_bytes)) def get_info(self) -> str: """Get Fapi information, containing library info, TPM capabilities and more. Raises: TSS2_Exception: If Fapi returned an error code. Returns: str: JSON-encoded info string. """ info = ffi.new("char **") ret = lib.Fapi_GetInfo(self._ctx, info) _chkrc(ret) return ffi.string(_get_dptr(info, lib.Fapi_Free)).decode(self.encoding) def list(self, search_path: Optional[Union[bytes, str]] = None) -> List[str]: """Get a list of all Fapi current object paths. Args: search_path (bytes or str): If given, only list children of `search_path`. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. Returns: List[str]: List of all current Fapi object paths. """ search_path = _to_bytes_or_null(search_path, allow_null=False) path_list = ffi.new("char **") ret = lib.Fapi_List(self._ctx, search_path, path_list) _chkrc(ret) return ( ffi.string(_get_dptr(path_list, lib.Fapi_Free)) .decode(self.encoding) .split(":") ) def create_key( self, path: Union[bytes, str], type_: Optional[Union[bytes, str]] = None, # TODO enum policy_path: Optional[Union[bytes, str]] = None, auth_value: Optional[Union[bytes, str]] = None, exists_ok: bool = False, ) -> bool: """Create a cryptographic key inside the TPM. Args: path (bytes or str): Path to the new key object, e.g. `/HS/SRK/new_signing_key`. type_ (bytes or str): Comma separated list. Possible values: system, sign, decrypt, restricted, exportable, noda, 0x81000000. Defaults to None. policy_path (bytes or str): The path to the policy which will be associated with the key. Defaults to None. auth_value (bytes or str): Password to key. Defaults to None. exists_ok (bool): Do not throw a TSS2_Exception if an object with the given path already exists. Defaults to False. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bool: True if the key was created. False otherwise. """ path = _to_bytes_or_null(path) type_ = _to_bytes_or_null(type_) policy_path = _to_bytes_or_null(policy_path) auth_value = _to_bytes_or_null(auth_value) ret = lib.Fapi_CreateKey(self._ctx, path, type_, policy_path, auth_value) _chkrc( ret, acceptable=lib.TSS2_FAPI_RC_PATH_ALREADY_EXISTS if exists_ok else None ) return ret == lib.TPM2_RC_SUCCESS def sign( self, path: Union[bytes, str], digest: bytes, padding: Optional[Union[bytes, str]] = None, # TODO enum ) -> Tuple[bytes, str, str]: """Create a signature over a given digest. Args: path (bytes or str): Path to the signing key. digest (bytes): Digest to sign. padding (bytes or str): `"rsa_ssa"` or `"rsa_pss"`. Defaults to None (using the scheme specified in the crypto profile). Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[bytes, str, str]: (signature (DER), public key (PEM), certificate (PEM)) """ path = _to_bytes_or_null(path) padding = _to_bytes_or_null(padding) # enum digest = _to_bytes_or_null(digest) signature = ffi.new("uint8_t **") signature_size = ffi.new("size_t *") public_key = ffi.new("char **") certificate = ffi.new("char **") ret = lib.Fapi_Sign( self._ctx, path, padding, digest, len(digest), signature, signature_size, public_key, certificate, ) _chkrc(ret) return ( bytes(ffi.unpack(_get_dptr(signature, lib.Fapi_Free), signature_size[0])), ffi.string(_get_dptr(public_key, lib.Fapi_Free)), ffi.string(_get_dptr(certificate, lib.Fapi_Free)), ) def verify_signature( self, path: Union[bytes, str], digest: bytes, signature: bytes ): """Verify a signature on a given digest. Args: path (bytes or str): Path to the signing key. digest (bytes): Digest which was signed. signature (bytes): Signature to be verified. Raises: TSS2_Exception: If Fapi returned an error code, e.g. if the signature cannot be verified successfully. """ path = _to_bytes_or_null(path) ret = lib.Fapi_VerifySignature( self._ctx, path, digest, len(digest), signature, len(signature) ) _chkrc(ret) def encrypt( self, path: Union[bytes, str], plaintext: Union[bytes, str] ) -> bytes: # TODO difference seal/unseal """Encrypt the plaintext and return the ciphertext. Args: path (bytes or str): The decrypt key used for encryption. plaintext (bytes or str): The data to be encrypted. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The ciphertext. """ _check_bug_fixed( fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"], details="Faulty free of FAPI Encrypt might lead to Segmentation Fault. See https://github.com/tpm2-software/tpm2-tss/issues/2092", ) path = _to_bytes_or_null(path) plaintext = _to_bytes_or_null(plaintext) ciphertext = ffi.new("uint8_t **") ciphertext_size = ffi.new("size_t *") ret = lib.Fapi_Encrypt( self._ctx, path, plaintext, len(plaintext), ciphertext, ciphertext_size ) _chkrc(ret) return bytes( ffi.unpack(_get_dptr(ciphertext, lib.Fapi_Free), ciphertext_size[0]) ) def decrypt(self, path: Union[bytes, str], ciphertext: bytes) -> bytes: """Decrypt the ciphertext and return the plaintext. Args: path (bytes or str): The decrypt key used for decryption. ciphertext (bytes or str): The data to be decrypted. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The plaintext. """ path = _to_bytes_or_null(path) plaintext = ffi.new("uint8_t **") plaintext_size = ffi.new("size_t *") ret = lib.Fapi_Decrypt( self._ctx, path, ciphertext, len(ciphertext), plaintext, plaintext_size ) _chkrc(ret) return bytes(ffi.unpack(plaintext[0], plaintext_size[0])) def create_seal( self, path: Union[bytes, str], data: Optional[Union[bytes, str]] = None, type_: Optional[Union[bytes, str]] = None, policy_path: Optional[Union[bytes, str]] = None, auth_value: Optional[Union[bytes, str]] = None, size: Optional[int] = None, exists_ok: bool = False, ) -> bool: """Create a Fapi sealed (= encrypted) object, that is data sealed a Fapi parent key. Oftentimes, the data is a digest. Args: path (bytes or str): The path of the new sealed object. data (bytes or str): Data to be sealed (often a digest). If None, random data will be generated. Defaults to None. type_ (bytes or str): Comma separated list. Possible values: system, sign, decrypt, restricted, exportable, noda, 0x81000000. Defaults to None. policy_path (bytes or str): The path to the policy which will be associated with the sealed object. Defaults to None. auth_value (bytes or str): Password to protect the new sealed object. Defaults to None. size (int): If data is None, random bytes of length size are generated. Parameters data and size cannot be given at the same time. Defaults to None. exists_ok (bool): Do not throw a TSS2_Exception if an object with the given path already exists. Defaults to False. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bool: True if the sealed object was created. False otherwise. """ path = _to_bytes_or_null(path) if data is not None and size is not None: raise ValueError("Parameters data and size cannot be given at same time.") if data is None and size is None: raise ValueError("Either parameter data or parameter size must be given.") if data is None: data_len = size else: data_len = len(data) data = _to_bytes_or_null(data) type_ = _to_bytes_or_null(type_) policy_path = _to_bytes_or_null(policy_path) auth_value = _to_bytes_or_null(auth_value) ret = lib.Fapi_CreateSeal( self._ctx, path, type_, data_len, policy_path, auth_value, data ) _chkrc( ret, acceptable=lib.TSS2_FAPI_RC_PATH_ALREADY_EXISTS if exists_ok else None ) return ret == lib.TPM2_RC_SUCCESS def unseal(self, path: Union[bytes, str]) -> bytes: """Unseal a sealed (= encrypted) Fapi object and return the data in plaintext. Args: path (Union[bytes, str]): The path to the sealed object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The unsealed data in plaintext. """ path = _to_bytes_or_null(path) data = ffi.new("uint8_t **") data_size = ffi.new("size_t *") ret = lib.Fapi_Unseal(self._ctx, path, data, data_size) _chkrc(ret) return bytes(ffi.unpack(_get_dptr(data, lib.Fapi_Free), data_size[0])) def import_object( self, path: Union[bytes, str], import_data: Union[bytes, str], exists_ok: bool = False, ) -> bool: """Import policy, policy template or key into the keystore. Args: path (bytes or str): Path of the future Fapi object. import_data (bytes or str): JSON-encoded data to import. exists_ok (bool): Do not throw a TSS2_Exception if an object with the given path already exists. Defaults to False. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bool: True if the object was imported. False otherwise. """ _check_bug_fixed( fixed_in="3.2", details="FAPI Import will overwrite existing objects with same path silently. See https://github.com/tpm2-software/tpm2-tss/issues/2028", ) path = _to_bytes_or_null(path) import_data = _to_bytes_or_null(import_data) ret = lib.Fapi_Import(self._ctx, path, import_data) _chkrc( ret, acceptable=lib.TSS2_FAPI_RC_PATH_ALREADY_EXISTS if exists_ok else None ) return ret == lib.TPM2_RC_SUCCESS def delete(self, path: Union[bytes, str]) -> None: """Delete Fapi object. Args: path (bytes or str): Path to the Fapi object to delete. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) ret = lib.Fapi_Delete(self._ctx, path) _chkrc(ret) def change_auth( self, path: Union[bytes, str], auth_value: Optional[Union[bytes, str]] = None ) -> None: """Change the password to a Fapi object. Args: path (bytes or str): Path to the Fapi object. auth_value (bytes or str): New password. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) auth_value = _to_bytes_or_null(auth_value) ret = lib.Fapi_ChangeAuth(self._ctx, path, auth_value) _chkrc(ret) def export_key( self, path: Union[bytes, str], new_path: Union[bytes, str] = None ) -> str: """Export a Fapi object as a JSON-encoded string. Args: path (bytes or str): Path to the existing Fapi object. new_path (bytes or str): New path to the Fapi object. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. Returns: str: The exported data. """ path = _to_bytes_or_null(path) new_path = _to_bytes_or_null(new_path) exported_data = ffi.new("char **") ret = lib.Fapi_ExportKey(self._ctx, path, new_path, exported_data) _chkrc(ret) return ffi.string(_get_dptr(exported_data, lib.Fapi_Free)).decode(self.encoding) def set_description( self, path: Union[bytes, str], description: Optional[Union[bytes, str]] = None ) -> None: """Set the description of a Fapi object. Args: path (bytes or str): Path to the Fapi object. description (bytes or str): New description of the Fapi object. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) description = _to_bytes_or_null(description) ret = lib.Fapi_SetDescription(self._ctx, path, description) _chkrc(ret) def get_description(self, path: Union[bytes, str] = None) -> str: """Get the description of a Fapi object. Args: path (bytes or str): Path to the Fapi object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: str: The description of the Fapi object. """ path = _to_bytes_or_null(path) description = ffi.new("char **") ret = lib.Fapi_GetDescription(self._ctx, path, description) _chkrc(ret) # description is guaranteed to be a null-terminated string return ffi.string(_get_dptr(description, lib.Fapi_Free)).decode() def set_app_data( self, path: Union[bytes, str], app_data: Optional[Union[bytes, str]] = None ) -> None: """Add custom application data to a Fapi object. This data is saved alongside the object and can be used by the application. Args: path (bytes or str): Path to the Fapi object. app_data (bytes or str): Custom application data to be associated with the Fapi object. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) if app_data is None: app_data_len = 0 else: app_data_len = len(app_data) app_data = _to_bytes_or_null(app_data) ret = lib.Fapi_SetAppData(self._ctx, path, app_data, app_data_len) _chkrc(ret) def get_app_data(self, path: Union[bytes, str]) -> Optional[bytes]: """Get the custom application data of a Fapi object. Args: path (bytes or str): Path to the Fapi object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Optional[bytes]: The application data or None. """ path = _to_bytes_or_null(path) app_data = ffi.new("uint8_t **") app_data_size = ffi.new("size_t *") ret = lib.Fapi_GetAppData(self._ctx, path, app_data, app_data_size) _chkrc(ret) if app_data[0] == ffi.NULL: return None return bytes(ffi.unpack(_get_dptr(app_data, lib.Fapi_Free), app_data_size[0])) def set_certificate( self, path: Union[bytes, str], certificate: Optional[Union[bytes, str]] = None ) -> None: """Add x509 certificate to a Fapi object. This data is saved alongside the object and can be used by the application. Args: path (bytes or str): Path to the Fapi object. certificate (bytes or str): x509 certificate to be associated with the Fapi object. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) certificate = _to_bytes_or_null(certificate) ret = lib.Fapi_SetCertificate(self._ctx, path, certificate) _chkrc(ret) def get_certificate(self, path: Union[bytes, str]) -> str: """Get the custom application data of a Fapi object. Args: path (bytes or str): Path to the Fapi object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The application data. """ path = _to_bytes_or_null(path) certificate = ffi.new("char **") ret = lib.Fapi_GetCertificate(self._ctx, path, certificate) _chkrc(ret) # certificate is guaranteed to be a null-terminated string return ffi.string(_get_dptr(certificate, lib.Fapi_Free)).decode() def get_platform_certificates(self, no_cert_ok: bool = False) -> bytes: """Get the platform certificate and the so-called delta certificates. Args: no_cert_ok (bool): If True, an empty byte string is returned if no certificate is found. If False, in this case a TSS2_Exception is raised. Defaults to False. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bytes: The platform certificates """ _check_bug_fixed( fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"], details="FAPI Get Platform Certificate might lead wrong sequence errors. See https://github.com/tpm2-software/tpm2-tss/issues/2091", ) # TODO split certificates into list # TODO why bytes? is this DER? certificate = ffi.new("uint8_t **") certificates_size = ffi.new("size_t *") ret = lib.Fapi_GetPlatformCertificates( self._ctx, certificate, certificates_size ) _chkrc(ret, acceptable=lib.TSS2_FAPI_RC_NO_CERT if no_cert_ok else None) if no_cert_ok and ret == lib.TSS2_FAPI_RC_NO_CERT: return b"" return bytes( ffi.unpack(_get_dptr(certificate, lib.Fapi_Free), certificates_size) ) def get_tpm_blobs( self, path: Union[bytes, str] ) -> Tuple[TPM2B_PUBLIC, TPM2B_PRIVATE, str]: """Get the TPM data blobs and the policy associates with a Fapi object. Args: path (bytes or str): Path to the Fapi object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[TPM2B_PUBLIC, TPM2B_PRIVATE, str]: (tpm_2b_public, tpm_2b_private, policy) """ path = _to_bytes_or_null(path) tpm_2b_public = ffi.new("uint8_t **") tpm_2b_public_size = ffi.new("size_t *") tpm_2b_private = ffi.new("uint8_t **") tpm_2b_private_size = ffi.new("size_t *") policy = ffi.new("char **") ret = lib.Fapi_GetTpmBlobs( self._ctx, path, tpm_2b_public, tpm_2b_public_size, tpm_2b_private, tpm_2b_private_size, policy, ) _chkrc(ret) policy_str = ffi.string(policy[0]).decode(self.encoding) tpm_2b_public_buffer = bytes( ffi.buffer(tpm_2b_public[0], tpm_2b_public_size[0]) ) tpm_2b_public_unmarsh, _ = TPM2B_PUBLIC.unmarshal(tpm_2b_public_buffer) tpm_2b_private_buffer = bytes( ffi.buffer(tpm_2b_private[0], tpm_2b_private_size[0]) ) tpm_2b_private_unmarsh, _ = TPM2B_PRIVATE.unmarshal(tpm_2b_private_buffer) return ( tpm_2b_public_unmarsh, tpm_2b_private_unmarsh, policy_str, ) def get_esys_blob(self, path: Union[bytes, str]) -> Tuple[bytes, Any]: """Return the ESAPI binary blob associated with a Fapi object. This blob can be easily loaded with :meth:`~tpm2_pytss.ESAPI.load_blob()`. Args: path (bytes or str): Path to the Fapi object. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[bytes, Any]: A tuple of the binary blob and its type (:const:`constants.FAPI_ESYSBLOB.CONTEXTLOAD` or :const:`constants.FAPI_ESYSBLOB.DESERIALIZE`) """ path = _to_bytes_or_null(path) type_ = ffi.new("uint8_t *") data = ffi.new("uint8_t **") length = ffi.new("size_t *") ret = lib.Fapi_GetEsysBlob(self._ctx, path, type_, data, length) _chkrc(ret) return bytes(ffi.unpack(_get_dptr(data, lib.Fapi_Free), length[0])), type_[0] def export_policy(self, path: Union[bytes, str]) -> str: """Export a policy from the key store as a JSON-encoded string. Args: path (bytes or str): Path to the FAPI policy. Raises: TSS2_Exception: If Fapi returned an error code. Returns: str: JSON-encoded policy. """ path = _to_bytes_or_null(path) policy = ffi.new("char **") ret = lib.Fapi_ExportPolicy(self._ctx, path, policy) _chkrc(ret) return ffi.string(_get_dptr(policy, lib.Fapi_Free)).decode() def authorize_policy( self, policy_path: Union[bytes, str], key_path: Union[bytes, str], policy_ref: Optional[Union[bytes, str]] = None, ): """Specify the underlying policy/policies for a policy Authorize. Args: policy_path (bytes or str): Path to the underlying policy. key_path (bytes or str): Path to the key associated with the policy Authorize. policy_ref (bytes or str): Additional application data (e.g. a reference to another policy). Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ policy_path = _to_bytes_or_null(policy_path) key_path = _to_bytes_or_null(key_path) if policy_ref is None: policy_ref_len = 0 else: policy_ref_len = len(policy_ref) policy_ref = _to_bytes_or_null(policy_ref) ret = lib.Fapi_AuthorizePolicy( self._ctx, policy_path, key_path, policy_ref, policy_ref_len ) _chkrc(ret) def pcr_read(self, index: int) -> Tuple[bytes, str]: """Read the value of a TPM Platform Configuration Register (PCR) and its associated event log. Args: index (int): Index of the PCR (in the range of 0-23 in most cases). Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[bytes, str]: (pcr_value, event_log) """ value = ffi.new("uint8_t **") value_size = ffi.new("size_t *") log = ffi.new("char **") ret = lib.Fapi_PcrRead(self._ctx, index, value, value_size, log) _chkrc(ret) return ( bytes(ffi.unpack(_get_dptr(value, lib.Fapi_Free), value_size[0])), ffi.string(_get_dptr(log, lib.Fapi_Free)).decode(), ) def pcr_extend( self, index: int, data: Union[bytes, str], log: Optional[Union[bytes, str]] = None, ) -> None: """Extend the value of a TPM Platform Configuration Register (PCR). The data given by the user and the previous PCR value are hashed together. The resulting digest is stored as the new PCR value. As a result, a PCR value depends on every piece of data given via the extend command (until the PCR is reset). Args: index (int): Index of the PCR (in the range of 0-23 in most cases). data (bytes or str): Input data to the extend operation. log (bytes or str): JSON-encoded event log data. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[bytes, str]: PCR value and its associated event log. """ # TODO "extend", formula in doc log = _to_bytes_or_null(log) data = _to_bytes_or_null(data) ret = lib.Fapi_PcrExtend(self._ctx, index, data, len(data), log) _chkrc(ret) def quote( self, path: Union[bytes, str], pcrs: List[int], quote_type: Optional[Union[bytes, str]] = None, qualifying_data: Optional[Union[bytes, str]] = None, ) -> Tuple[str, bytes, str, str]: """Create a TPM quote, that is a signed data structure of the TPM Platform Configuration Registers (PCRs), reset count, firmware version and more. Args: path (bytes or str): Path to the key used for signing. pcrs (List[int]): List of PCR indices to be included in the quote. quote_type (bytes or str): Type of quote to create. The default "TPM-Quote" is used if None is given. Defaults to None. qualifying_data (bytes or str): Additional application-defined data. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[str, bytes, str, str]: info, signature, pcr_log, certificate """ _check_bug_fixed( fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"], details="Multiple calls of FAPI Quote might lead to TPM out of memory errors. See https://github.com/tpm2-software/tpm2-tss/issues/2084", ) path = _to_bytes_or_null(path) quote_type = _to_bytes_or_null(quote_type) if qualifying_data is None: qualifying_data_len = 0 else: qualifying_data_len = len(qualifying_data) qualifying_data = _to_bytes_or_null(qualifying_data) quote_info = ffi.new("char **") signature = ffi.new("uint8_t **") signature_len = ffi.new("size_t *") pcr_log = ffi.new("char **") certificate = ffi.new("char **") ret = lib.Fapi_Quote( self._ctx, pcrs, len(pcrs), path, quote_type, qualifying_data, qualifying_data_len, quote_info, signature, signature_len, pcr_log, certificate, ) _chkrc(ret) return ( ffi.string(_get_dptr(quote_info, lib.Fapi_Free)).decode(), bytes(ffi.unpack(_get_dptr(signature, lib.Fapi_Free), signature_len[0])), ffi.string(_get_dptr(pcr_log, lib.Fapi_Free)).decode(), ffi.string( _get_dptr(certificate, lib.Fapi_Free) or ffi.new("char *") ).decode(), ) def verify_quote( self, path: Union[bytes, str], signature: bytes, quote_info: Union[bytes, str], qualifying_data: Optional[Union[bytes, str]] = None, pcr_log: Optional[Union[bytes, str]] = None, ): """Verify the signature to a TPM quote. Args: path (bytes or str): Path to the key used for verifying the signature. signature (bytes): Signature to the quote. quote_info (bytes or str): Quote info structure. qualifying_data (bytes or str): Additional application-defined data. Defaults to None. pcr_log (bytes or str): JSON-encoded PCR log entry. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) signature = _to_bytes_or_null(signature) if qualifying_data is None: qualifying_data_len = 0 else: qualifying_data_len = len(qualifying_data) qualifying_data = _to_bytes_or_null(qualifying_data) quote_info = _to_bytes_or_null(quote_info) pcr_log = _to_bytes_or_null(pcr_log) ret = lib.Fapi_VerifyQuote( self._ctx, path, qualifying_data, qualifying_data_len, quote_info, signature, len(signature), pcr_log, ) _chkrc(ret) def create_nv( self, path: Union[bytes, str], size: int, type_: Optional[Union[bytes, str]] = None, policy_path: Optional[Union[bytes, str]] = None, auth_value: Optional[Union[bytes, str]] = None, exists_ok: bool = False, ) -> bool: """Create non-volatile (NV) storage on the TPM. Args: path (bytes or str): Path to the NV storage area. size (int): Size of the storage area in bytes. type_ (bytes or str): Type of the storage area. A combination of `bitfield`, `counter`, `pcr`, `system`, `noda`. Defaults to None. policy_path (bytes or str): The path to the policy which will be associated with the storage area. Defaults to None. auth_value (bytes or str): Password to protect the new storage area. Defaults to None. exists_ok (bool): Do not throw a TSS2_Exception if a storage area with the given path already exists. Defaults to False. Raises: TSS2_Exception: If Fapi returned an error code. Returns: bool: True if the storage area was created. False otherwise. """ path = _to_bytes_or_null(path) type_ = _to_bytes_or_null(type_) policy_path = _to_bytes_or_null(policy_path) auth_value = _to_bytes_or_null(auth_value) ret = lib.Fapi_CreateNv(self._ctx, path, type_, size, policy_path, auth_value) _chkrc( ret, acceptable=lib.TSS2_FAPI_RC_PATH_ALREADY_EXISTS if exists_ok else None ) return ret == lib.TPM2_RC_SUCCESS def nv_read(self, path: Union[bytes, str]) -> Tuple[bytes, str]: """Read from non-volatile (NV) TPM storage. Args: path (bytes or str): Path to the NV storage area. Raises: TSS2_Exception: If Fapi returned an error code. Returns: Tuple[bytes, str]: Data stored in the NV storage area and its associated event log. """ path = _to_bytes_or_null(path) data = ffi.new("uint8_t **") data_size = ffi.new("size_t *") log = ffi.new("char **") ret = lib.Fapi_NvRead(self._ctx, path, data, data_size, log) _chkrc(ret) return ( bytes(ffi.unpack(_get_dptr(data, lib.Fapi_Free), data_size[0])), ffi.string(_get_dptr(log, lib.Fapi_Free)).decode(), ) def nv_write(self, path: Union[bytes, str], data: Union[bytes, str]) -> None: """Write data to a non-volatile (NV) TPM storage and the associated event log. Args: path (bytes or str): Path to the NV storage area. data (bytes or str): Data to write to the NV storage area. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) data = _to_bytes_or_null(data) ret = lib.Fapi_NvWrite(self._ctx, path, data, len(data)) _chkrc(ret) def nv_extend( self, path: Union[bytes, str], data: Union[bytes, str], log: Optional[Union[bytes, str]] = None, ) -> None: """Perform an extend operation on a non-volatile TPM storage area. Requires an NV object of type `pcr`. For more information on the extend operation, see :meth:`~tpm2_pytss.FAPI.pcr_extend`. Args: path (bytes or str): Path to the NV storage area. data (bytes or str): Input data to the extend operation. log (bytes or str): JSON-encoded event to be associated with this change. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) data = _to_bytes_or_null(data) log = _to_bytes_or_null(log) ret = lib.Fapi_NvExtend(self._ctx, path, data, len(data), log) _chkrc(ret) def nv_increment(self, path: Union[bytes, str]) -> None: """Increment the counter value stored in non-volatile (NV) TPM storage. Args: path (bytes or str): Path to the NV storage area. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) ret = lib.Fapi_NvIncrement(self._ctx, path) _chkrc(ret) def nv_set_bits(self, path: Union[bytes, str], bitmap: int) -> None: """Set bits of bitfielad, stored in non-volatile (NV) TPM storage. Args: path (bytes or str): Path to the NV storage area. bitmap (int): Bits to set in the NV storage area. Raises: TSS2_Exception: If Fapi returned an error code. """ path = _to_bytes_or_null(path) ret = lib.Fapi_NvSetBits(self._ctx, path, bitmap) _chkrc(ret) def write_authorize_nv( self, nv_path: Union[bytes, str], policy_path: Union[bytes, str] ) -> None: """Write a policy to non-volatile (NV) TPM storage. Args: nv_path (bytes or str): Path to the NV storage area. policy_path (bytes or str): Path to the policy to be written. Raises: TSS2_Exception: If Fapi returned an error code. """ nv_path = _to_bytes_or_null(nv_path) policy_path = _to_bytes_or_null(policy_path) ret = lib.Fapi_WriteAuthorizeNv(self._ctx, nv_path, policy_path) _chkrc(ret) def set_auth_callback( self, callback: Optional[ Callable[[str, str, Optional[Any]], Union[bytes, str]] ] = None, user_data: Optional[Any] = None, ) -> None: """Register a callback that provides the password for Fapi objects when needed. Typically, this callback implements a password prompt. If `callback` is None, the callback function is reset. Args: callback (Optional[Callable[[str, str, Optional[Any]], Union[bytes, str]]]): A callback function `callback(path, description, user_data=None)` which returns the password (:class:`str`). Defaults to None. user_data (Any): Bytes that will be handed to the callback. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. RuntimeError: If callback is None and user_data is NOT None. """ if callback is None and user_data is not None: raise RuntimeError("If callback is None, user_data must be None, too.") if callback: cb_udata = _FAPI_CB_UDATA(callback, user_data) cb_user_data_handle = ffi.new_handle(cb_udata) # keep this alive, overwrite old so it be gc'd self._callback_metadata["auth"] = cb_user_data_handle lib_callback = lib._fapi_auth_callback else: lib_callback = ffi.NULL cb_user_data_handle = ffi.NULL self._callback_metadata["auth"] = None ret = lib.Fapi_SetAuthCB(self._ctx, lib_callback, cb_user_data_handle) _chkrc(ret) def set_branch_callback( self, callback: Optional[Callable[[str, str, List[str], Optional[Any]], int]] = None, user_data: Optional[Any] = None, ): """Set the Fapi policy branch callback, called to decide which policy path to take in a policy Or. If `callback` is None, the callback function is reset. Args: callback (Callable[[str, str, List[str], Optional[bytes]], int]): A callback function `callback(path, description, branch_names, user_data=None)` which returns the index (:class:`int`) of the selected branch in `branch_names`. Defaults to None. user_data (bytes or str): Custom data passed to the callback function. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. RuntimeError: If callback is None and user_data is NOT None. """ if callback is None: _check_bug_fixed( fixed_in="3.1", backports=["2.4.3", "3.0.1", "3.1.0"], details="A NULL FAPI SetBranchCallback Action might lead to crashes. See https://github.com/tpm2-software/tpm2-tss/pull/2500", ) if callback is None and user_data is not None: raise RuntimeError("If callback is None, user_data must be None, too.") if callback: cb_udata = _FAPI_CB_UDATA(callback, user_data) cb_user_data_handle = ffi.new_handle(cb_udata) # keep this alive, overwrite old so it be gc'd self._callback_metadata["branch"] = cb_user_data_handle lib_callback = lib._fapi_branch_callback else: lib_callback = ffi.NULL cb_user_data_handle = ffi.NULL self._callback_metadata["branch"] = None ret = lib.Fapi_SetBranchCB(self._ctx, lib_callback, cb_user_data_handle) _chkrc(ret) def set_sign_callback( self, callback: Optional[ Callable[[str, str, str, str, int, bytes, Optional[Any]], bytes] ] = None, user_data: Optional[Any] = None, ): """Set the Fapi signing callback which is called to satisfy the policy Signed. If `callback` is None, the callback function is reset. Args: callback (Callable[[str, str, str, str, int, bytes, Optional[bytes]], bytes]): A callback function `callback(path, description, public_key, public_key_hint, hash_alg, data_to_sign, user_data=None)` which returns a signature (:class:`bytes`) of `data_to_sign`. Defaults to None. user_data (Any): Custom data passed to the callback function. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. RuntimeError: If callback is None and user_data is NOT None. """ _check_bug_fixed( fixed_in="3.2", details="FAPI PolicySigned default nameAlg might be SHA1 unexpectedly. See https://github.com/tpm2-software/tpm2-tss/issues/2080. Fixed in https://github.com/tpm2-software/tpm2-tss/commit/b843960b6e601a786b469832392dc0a12e13cf34", ) if callback is None and user_data is not None: raise RuntimeError("If callback is None, user_data must be None, too.") if callback: cb_udata = _FAPI_CB_UDATA(callback, user_data) cb_user_data_handle = ffi.new_handle(cb_udata) # keep this alive, overwrite old so it be gc'd self._callback_metadata["sign"] = cb_user_data_handle lib_callback = lib._fapi_sign_callback else: lib_callback = ffi.NULL cb_user_data_handle = ffi.NULL self._callback_metadata["sign"] = None ret = lib.Fapi_SetSignCB(self._ctx, lib_callback, cb_user_data_handle) _chkrc(ret) def set_policy_action_callback( self, callback: Optional[Callable[[str, str, Optional[bytes]], None]] = None, user_data: Optional[Any] = None, ): """Set the policy Action callback which is called to satisfy the policy Action. If `callback` is None, the callback function is reset. Args: callback (Callable[[str, str, Optional[bytes]], None]): A callback function `callback(path, action, user_data=None)`. Defaults to None. user_data (Any): Custom data passed to the callback function. Defaults to None. Raises: TSS2_Exception: If Fapi returned an error code. RuntimeError: If callback is None and user_data is NOT None. """ _check_bug_fixed( fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"], details="FAPI Policy Action might lead to crashes. See https://github.com/tpm2-software/tpm2-tss/issues/2089", ) if callback is None and user_data is not None: raise RuntimeError("If callback is None, user_data must be None, too.") if callback: cb_udata = _FAPI_CB_UDATA(callback, user_data) cb_user_data_handle = ffi.new_handle(cb_udata) # keep this alive, overwrite old so it be gc'd self._callback_metadata["policy"] = cb_user_data_handle lib_callback = lib._fapi_policy_action_callback else: lib_callback = ffi.NULL cb_user_data_handle = ffi.NULL self._callback_metadata["policy"] = None ret = lib.Fapi_SetPolicyActionCB(self._ctx, lib_callback, cb_user_data_handle) _chkrc(ret) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/TCTI.py000066400000000000000000000474211506405471500203050ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from ._libtpm2_pytss import ffi, lib from .internal.utils import _chkrc from .constants import TSS2_RC, TPM2_RC from .TSS2_Exception import TSS2_Exception import os from typing import Optional, Tuple, Union class PollData(object): """Initialize a PollData object with OS specific details. Initialize a PollData object that holds all OS specific state and metadata information for using in the platforms specific asynchronous IO "polling" system. For Linux this is Poll, Windows is WaitForSingleObject or other interfaces. Only posix systems currently support the events attribute. The system is identified by `os.name`. Args: fd (int): The File Descriptor(fd) for posix systems or Opque Handle for other systems. events (int): The event mask, only for posix systems. Returns: An instance of the PollData class. """ def __init__(self, fd: int = -1, events: int = -1): self._fd = fd self._events = events @property def fd(self) -> int: """Gets the File Descriptor or Handle for the asynch I/O wait event. Returns: The fd or handle. """ return self._fd @property def handle(self) -> int: """Gets the File Descriptor or Handle for the asynch I/O wait event. Same as attribute fd. Returns: The fd or handle. """ return self._fd @property def events(self) -> int: """Gets the Event Mask for the asynch I/O wait event. Suitable for poll. Returns: The poll event mask. Raises: NotImplementedError if os.name does not equal "posix". """ if os.name != "posix": raise NotImplementedError( f"Non POSIX os detected, pollin events not supported, got: {os.name}" ) return self._events def common_checks(version=1, null_ok=False): def decorator(func): def wrapper(self, *args, **kwargs): def camel_case(s): from re import sub s = sub(r"(_|-)+", " ", s).title().replace(" ", "") return "".join([s[0].lower(), s[1:]]) if self._v1.version < 1: raise TSS2_Exception(TSS2_RC.TCTI_RC_ABI_MISMATCH) sub_struct = getattr(self, f"_v{version}") if sub_struct is None: raise TSS2_Exception(TSS2_RC.TCTI_RC_NOT_IMPLEMENTED) method = func.__name__ method = camel_case(method) got_method = getattr(sub_struct, method) if not null_ok and got_method == ffi.NULL: raise TSS2_Exception(TSS2_RC.TCTI_RC_NOT_IMPLEMENTED) try: self._clear_exceptions() return func(self, *args, **kwargs) except Exception as e: e = self._get_current_exception(e) self._clear_exceptions() raise e return wrapper return decorator class TCTI: """Initialize a TCTI object. Initialize a TCTI from a NATIVE instantiated TCTI. Args: ctx (ffi.CData): A TSS2_TCTI_CONTEXT * variable. This would be returned from a TCTIs initialize or TCTILdr routine. Returns: An instance of a TCTI. """ def __init__(self, ctx: ffi.CData): self._v1 = ffi.cast("TSS2_TCTI_CONTEXT_COMMON_V1 *", ctx) if self._v1.version == 2: self._v2 = ffi.cast("TSS2_TCTI_CONTEXT_COMMON_V2 *", ctx) else: self._v2 = None self._ctx = ctx # record the last exception so we can throw across the C boundry without # everything becoming an unknown TSS2_Exception(TSS2_RC.TCTI_RC_GENERAL_FAILURE) # Normal TCTIs cannot make use of this, by Python TCTIs can. Add it to the base class # for subordinate TCTIs to use. This way the TCTI fn calls return the most helpful # error. self._last_exception = None def _set_last_exception(self, exc): self._last_exception = exc @property def _tcti_context(self): return self._ctx @property def magic(self) -> bytes: """Returns the MAGIC string of the TCTI. Returns: The magic byte string. """ # uint64_t in C land by default or let subclass control it magic_len = getattr(self, "_magic_len", 8) return self._v1.magic.to_bytes(magic_len, "big") @property def version(self) -> int: """Returns the VERSION number of the TCTI. This is the TCTI interface version NOT the release version of the TCTI. Ie if it implements version 1 or version 2 of the spec. Returns: The TCTI version number. """ return self._v1.version def _clear_exceptions(self): self._last_exception = None def _get_current_exception(self, e: Exception): x = self._last_exception return x if x is not None else e @common_checks() def transmit(self, command: bytes) -> None: """Transmits bytes to the TPM. Args: command (bytes): The bytes to transmit to the TPM. Returns: The TCTI version number. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ cmd = ffi.new("uint8_t []", command) clen = len(command) _chkrc(self._v1.transmit(self._ctx, clen, cmd)) @common_checks() def receive(self, size: int = 4096, timeout: int = -1) -> bytes: """Receives bytes from the TPM. Args: size (int): The maximum expected response size. Defaults to 4096. Negative values infer the default. timeout (int): The maximum time to wait for a response in milliseconds. Defaults to -1 which will wait indefinitely. Returns: The TPM response as bytes. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ if size < 0: size = 4096 resp = ffi.new("uint8_t []", b"\x00" * size) rsize = ffi.new("size_t *", size) _chkrc(self._v1.receive(self._ctx, rsize, resp, timeout)) return bytes(ffi.buffer(resp, rsize[0])) @common_checks(null_ok=True) def finalize(self): """Cleans up a TCTI's state and resources.""" if self._v1.finalize != ffi.NULL: self._v1.finalize(self._ctx) if self._last_exception: e = self._last_exception self._clear_exceptions() raise e @common_checks() def cancel(self) -> None: """Cancels a current transmit with the TPM. Some TCTIs may support the ability to cancel the current I/O Operation with the TPM. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ _chkrc(self._v1.cancel(self._ctx)) @common_checks() def get_poll_handles(self) -> Tuple[PollData]: """Gets the poll handles from the TPM. Returns: A tuple of PollData objects. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ nhandles = ffi.new("size_t *", 0) _chkrc(self._v1.getPollHandles(self._ctx, ffi.NULL, nhandles)) if nhandles[0] == 0: return () handles = ffi.new("TSS2_TCTI_POLL_HANDLE []", nhandles[0]) _chkrc(self._v1.getPollHandles(self._ctx, handles, nhandles)) rh = [] for i in range(0, nhandles[0]): if os.name == "posix": pd = PollData(handles[i].fd, handles[i].events) else: pd = PollData(handles[i]) rh.append(pd) return tuple(rh) @common_checks() def set_locality(self, locality: int) -> None: """Sets the locality of the current TCTI connection with the TPM. Locality is a value that specifies to the TPM whom is making the request. Ie firmware, OS, userspace, etc. For TCTIs and TPMs that support this, this interface allows one to set the locality. Args: locality (int): The locality value as an integer. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ _chkrc(self._v1.setLocality(self._ctx, locality)) @common_checks(version=2) def make_sticky(self, handle: int, sticky: Union[bool, int]) -> None: """Makes an object specified by handle not be flushed by a resource manager. Resource Managers (RM) MAY flush transient objects when the client disconnects. Thus this object would need to be re-established later, eg TPM2_Load command, this allows RMs that support the ability to mark this object as non-flushable. Raises: TSS2_Exception - Underlying TCTI errors Exception - Underlying Python TCTIs can return anything. """ hptr = ffi.new("TPM2_HANDLE *", handle) _chkrc(self._v2.makeSticky(self._ctx, hptr, sticky)) return hptr[0] def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.finalize() # Global callbacks @ffi.def_extern() def _tcti_transmit_wrapper(ctx, size, command): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_transmit"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: pi.do_transmit(bytes(ffi.buffer(command, size))) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_receive_wrapper(ctx, size, response, timeout): # Let the allocator know how much we need. pi = PyTCTI._cffi_cast(ctx) if response == ffi.NULL: size[0] = pi._max_size return TPM2_RC.SUCCESS if not hasattr(pi, "do_receive"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: resp = pi.do_receive(timeout) max_size = size[0] if len(resp) > max_size: raise TSS2_Exception(TSS2_RC.TCTI_RC_INSUFFICIENT_BUFFER) size[0] = len(resp) ffi.memmove(response, resp, len(resp)) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_cancel_wrapper(ctx): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_cancel"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: pi.do_cancel() except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_get_pollfds_wrapper(ctx, handles, cnt): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_get_poll_handles"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: # Populate a cache so Python implementors don't have to be called # for size and then fd's. FDs should be stable. if pi._poll_handle_cache is None: pi._poll_handle_cache = pi.do_get_poll_handles() # Support callers returning None or list if pi._poll_handle_cache is None: pi._poll_handle_cache = () # caller wants size for allocation if handles == ffi.NULL: cnt[0] = len(pi._poll_handle_cache) elif cnt[0] < len(pi._poll_handle_cache): raise TSS2_RC.TCTI_RC_INSUFFICIENT_BUFFER else: cnt[0] = len(pi._poll_handle_cache) # Enumerate didn't work here for i in range(0, cnt[0]): pd = pi._poll_handle_cache[i] # convert platform agnostic into CData if os.name == "posix": handles[i].fd = pd.fd handles[i].events = pd.events else: handles[i] = pd.handle except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_set_locality_wrapper(ctx, locality): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_set_locality"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: pi.do_set_locality(locality) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_make_sticky_wrapper(ctx, handle, sticky): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_make_sticky"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: pi.do_make_sticky(handle, bool(sticky)) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE pi._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_finalize_wrapper(ctx): pi = PyTCTI._cffi_cast(ctx) if not hasattr(pi, "do_finalize"): return try: pi.do_finalize() except Exception as e: pi._set_last_exception(e) class PyTCTI(TCTI): """Subclass for implementing a TCTI in Python. Extend this object and implement the following methods: - def do_transmit(self, command: bytes) -> None This method transmits a command buffer to the TPM. This method IS REQUIRED. - def do_receive(self, timeout: int) -> bytes: This method receives a response from the TPM and returns it. This method IS REQUIRED - def do_cancel(self) -> None: Cancels an I/O operation with the TPM. This method is OPTIONAL. - def do_get_poll_handles(self) -> Optional[Tuple[PollData]]: Retrieves PollData objects from the TCTI used for async I/O. This method is OPTIONAL. - def do_set_locality(self, locality: int) -> None: Sets the locality in which to communicate with the TPM. This method is OPTIONAL. - def do_make_sticky(self, handle: int, is_sticky: bool) -> None: Makes a handle sticky to persist across client exits with an RM. This method is OPTIONAL. - def do_finalize(self) -> None: Finalizes a TCTI, this is analogous to close on a file. This method is OPTIONAL. Note: All methods may throw exceptions as needed. Args: max_size (int): The size of the response buffer for callers to allocate. Defaults to 4096. magic (bytes): The magic value for the TCTI, may aid in debugging. Max length is 8, defaults to b"PYTCTI\x00\x00" Returns: An instance of the PyTCTI class. It's unusable as is, users should extend it. """ def __init__(self, max_size: int = 4096, magic: bytes = b"PYTCTI\x00\x00"): # PYTCTI ASCII FOR MAGIC: echo -n "5059544354490000" | xxd -r -cdata if len(magic) > 8: raise ValueError(f"Expected magic to be at most 8 bytes, got: {len(magic)}") cdata = self._cdata = ffi.new("PYTCTI_CONTEXT *") self._max_size = max_size self._poll_handle_cache = None self._magic_len = len(magic) cdata.common.v1.version = 2 cdata.common.v1.magic = int.from_bytes(magic, "big") cdata.common.v1.transmit = lib._tcti_transmit_wrapper cdata.common.v1.receive = lib._tcti_receive_wrapper cdata.common.v1.cancel = lib._tcti_cancel_wrapper cdata.common.v1.getPollHandles = lib._tcti_get_pollfds_wrapper cdata.common.v1.setLocality = lib._tcti_set_locality_wrapper cdata.common.makeSticky = lib._tcti_make_sticky_wrapper cdata.common.v1.finalize = lib._tcti_finalize_wrapper # Keep a pointer to this object in the TCTI Context to use later # This is how we multiplex N objects through a set of static # callbacks. Assign it to an object instance variable to prevent # it from getting GC cdata.thiz = self._thiz = ffi.new_handle(self) opaque = ffi.cast("TSS2_TCTI_CONTEXT *", cdata) super().__init__(opaque) @staticmethod def _cffi_cast(ctx): ctx = ffi.cast("PYTCTI_CONTEXT *", ctx) return ffi.from_handle(ctx.thiz) def do_transmit(self, command: bytes) -> None: """This method transmits a command buffer to the TPM. This method IS REQUIRED. Args: command (bytes): The bytes to send to the TPM. Raises: NotImplementedError: If a subclass has not implemented this. Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ raise NotImplementedError("Subclass needs to implement do_transmit") def do_receive(self, timeout: int) -> bytes: """This method receives a response from the TPM and returns it. This method IS REQUIRED. Args: timeout (int): The timeout in milliseconds to wait for the TPM. Negative values mean wait indefinitely. Raises: NotImplementedError: If a subclass has not implemented this. Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ raise NotImplementedError("Subclass needs to implement do_receive") def do_cancel(self) -> None: """Cancels an I/O operation with the TPM. This method is OPTIONAL. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def do_get_poll_handles(self) -> Optional[Tuple[PollData]]: """Retrieves PollData objects from the TCTI used for async I/O. This method is OPTIONAL. Returns: The tuple of PollData handles or None. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def do_set_locality(self, locality: int) -> None: """Sets the locality in which to communicate with the TPM. This method is OPTIONAL. Args: locality(int): The locality of communication with the TPM. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def do_make_sticky(self, handle: int, is_sticky: bool) -> None: """Makes a handle sticky to persist across client exits with a Resource Manager. This method is OPTIONAL. Note: A sticky object is one a RM doesn't flush when the client closes their connection. Args: handle(int): The TPM handle to make sticky. is_sticky(bool): True to make sticky, False to make it not sticky. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def do_finalize(self) -> None: """Finalizes a TCTI, this is analogous to close on a file. This method is OPTIONAL. Note: Native TCTIs do not return anything and thus cannot raise any errors. Python TCTIs MAY raise exceptions across this interface. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/TCTILdr.py000066400000000000000000000044741506405471500207500ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from ._libtpm2_pytss import lib, ffi from .TCTI import TCTI from .internal.utils import _chkrc class TCTILdr(TCTI): def __init__(self, name=None, conf=None): self._ctx_pp = ffi.new("TSS2_TCTI_CONTEXT **") if name is None: name = ffi.NULL elif isinstance(name, str): name = name.encode() if conf is None: conf = ffi.NULL elif isinstance(conf, str): conf = conf.encode() if not isinstance(name, (bytes, type(ffi.NULL))): raise TypeError(f"name must be of type bytes, got {type(name)}") if not isinstance(conf, (bytes, type(ffi.NULL))): raise TypeError(f"conf must be of type bytes, got {type(name)}") _chkrc(lib.Tss2_TctiLdr_Initialize_Ex(name, conf, self._ctx_pp)) super().__init__(self._ctx_pp[0]) self._name = name.decode() if name else "" self._conf = conf.decode() if conf else "" def __enter__(self): return self def __exit__(self, _type, value, traceback): self.close() def close(self): lib.Tss2_TctiLdr_Finalize(self._ctx_pp) self._ctx = ffi.NULL @classmethod def parse(cls, tcti_name_conf: str): chunks = tcti_name_conf.split(":", 1) if len(chunks) > 2: raise RuntimeError(f"Expected only 1 : in TCTI str, got {len(chunks)}") name = chunks[0] conf = chunks[1] if len(chunks) == 2 else None return cls(name, conf) @property def name(self): return self._name @property def conf(self): return self._conf @property def name_conf(self): return f"{self.name}:{self.conf}" if self.conf else self.name def __str__(self): return self.name_conf @staticmethod def is_available(name=None) -> bool: """Lookup the TCTI and return its availability Returns: True if the interface is available """ ctx_pp = ffi.new("TSS2_TCTI_INFO **") if name is None: name = ffi.NULL elif isinstance(name, str): name = name.encode() ret = lib.Tss2_TctiLdr_GetInfo(name, ctx_pp) if ret != lib.TPM2_RC_SUCCESS: return False lib.Tss2_TctiLdr_FreeInfo(ctx_pp) return True tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/TCTISPIHelper.py000066400000000000000000000230521506405471500220130ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .internal.utils import _chkrc, _lib_version_atleast from ._libtpm2_pytss import ffi, lib from .constants import TSS2_RC, TPM2_RC from .TSS2_Exception import TSS2_Exception from .TCTI import TCTI if not _lib_version_atleast("tss2-tcti-spi-helper", "0.0.0"): raise NotImplementedError("Package tss2-tcti-spi-helper not present") @ffi.def_extern() def _tcti_spi_helper_sleep_ms(userdata, milliseconds): thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_sleep_ms"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: thiz.on_sleep_ms(milliseconds) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_start_timeout(userdata, milliseconds): thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_start_timeout"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: thiz.on_start_timeout(milliseconds) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_timeout_expired(userdata, is_time_expired) -> bool: thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_timeout_expired"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: result = thiz.on_timeout_expired() is_time_expired[0] = result except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_spi_acquire(userdata): thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_start_timeout"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: thiz.on_spi_acquire() except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_spi_release(userdata): thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_spi_release"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: thiz.on_spi_release() except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_spi_transfer(userdata, data_out, data_in, cnt): thiz = TCTISPIHelper._cffi_cast(userdata) if not hasattr(thiz, "on_spi_transfer"): return TSS2_RC.TCTI_RC_NOT_IMPLEMENTED try: # setup for the transaction dout = None if data_out == ffi.NULL else bytes(ffi.buffer(data_out, cnt)) # call for transaction data_got = thiz.on_spi_transfer(dout) # handle response should None be OK? if data_got is None and data_in != ffi.NULL: raise RuntimeError("Response data CANNOT be None") elif data_got is None and data_in == ffi.NULL: return TPM2_RC.SUCCESS # current interface is hardcoded to full duplex, so input # must equal output if len(data_got) != cnt: raise ValueError( f"Transactions is expected to be {cnt} bytes, got {len(data_got)} bytes" ) # copy the data raw_data_got = ffi.from_buffer(data_got) ffi.memmove(data_in, raw_data_got, len(data_got)) except Exception as e: rc = e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.TCTI_RC_GENERAL_FAILURE thiz._set_last_exception(e) return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _tcti_spi_helper_finalize(userdata): thiz = TCTISPIHelper._cffi_cast(userdata) if hasattr(thiz, "on_finalize"): thiz.on_finalize(thiz) class TCTISPIHelper(TCTI): """The TCTI for interacting with SPI devices. Users should *extend* a TCTISPIHelper object and implement the following callbacks: All Users: - on_sleep_ms - on_start_timeout - on_timeout_expired - on_spi_transfer with_wait_state=true: - on_spi_acquire - on_spi_release Optional: - on_finalize Args: with_wait_state (bool): True if you intend to use wait states. Defaults to False. """ def __init__(self, with_wait_state=False): self._with_wait_state = with_wait_state size = ffi.new("size_t *") self._callbacks = ffi.new("TSS2_TCTI_SPI_HELPER_PLATFORM *") self._callbacks.sleep_ms = lib._tcti_spi_helper_sleep_ms self._callbacks.start_timeout = lib._tcti_spi_helper_start_timeout self._callbacks.timeout_expired = lib._tcti_spi_helper_timeout_expired self._callbacks.spi_transfer = lib._tcti_spi_helper_spi_transfer self._callbacks.finalize = lib._tcti_spi_helper_finalize self._callbacks.user_data = self._thiz = ffi.new_handle(self) missing_implementation = [] if self._with_wait_state: self._callbacks.spi_acquire = lib._tcti_spi_helper_spi_acquire self._callbacks.spi_release = lib._tcti_spi_helper_spi_release if "TCTISPIHelper.on_spi_acquire" in str(self.on_spi_acquire): missing_implementation.append("on_spi_acquire") if "TCTISPIHelper.on_spi_release" in str(self.on_spi_release): missing_implementation.append("on_spi_release") if "TCTISPIHelper.on_spi_transfer" in str(self.on_spi_transfer): missing_implementation.append("on_spi_transfer") if "TCTISPIHelper.on_timeout_expired" in str(self.on_timeout_expired): missing_implementation.append("on_timeout_expired") if "TCTISPIHelper.on_start_timeout" in str(self.on_start_timeout): missing_implementation.append("on_start_timeout") if "TCTISPIHelper.on_sleep_ms" in str(self.on_sleep_ms): missing_implementation.append("on_sleep_ms") if len(missing_implementation) > 0: raise NotImplementedError( f"Subclasses must implement {','.join(missing_implementation)}" ) _chkrc(lib.Tss2_Tcti_Spi_Helper_Init(ffi.NULL, size, self._callbacks)) self._tcti_mem = ffi.new(f"uint8_t [{size[0]}]") self._opaque_tcti_ctx = ffi.cast("TSS2_TCTI_CONTEXT *", self._tcti_mem) try: self._clear_exceptions() _chkrc( lib.Tss2_Tcti_Spi_Helper_Init( self._opaque_tcti_ctx, size, self._callbacks ) ) except Exception as e: e = self._get_current_exception(e) self._clear_exceptions() raise e super().__init__(self._opaque_tcti_ctx) @property def waitstate(self): """Gets the wait state property. Returns(bool): True if this TCTI implements wait states, false otherwise. """ return self._with_wait_state @staticmethod def _cffi_cast(userdata): return ffi.from_handle(userdata) def on_sleep_ms(self, milliseconds: int) -> None: """Sleeps for a specified amount of time in millisecons. This callback is REQUIRED. Args: milliseconds(int): The time to sleep. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def on_start_timeout(self, milliseconds: int) -> None: """Called when a timeout is occurring with the sleep duration in millisecons. This callback is REQUIRED. Args: milliseconds(int): The time to sleep. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def on_timeout_expired(self) -> bool: """Called to determine if a timeout is expired. This callback is REQUIRED. No errors may occur across this boundary. """ pass def on_spi_transfer(self, data_in: bytes) -> bytes: """Called to transfer data across the SPI bus. This callback is REQUIRED. Args: data_in(bytes): The data to send. Returns(bytes): The bytes to send. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def on_finalize(self) -> None: """Called when the TCTI is finalized. This callback is OPTIONAL. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass def on_spi_acquire(self) -> None: """Called when the SPI bus needs to be acquired for wait states. This callback is REQUIRED for WAIT STATES. No errors may occur across this boundary. """ pass def on_spi_release(self) -> None: """Called when the SPI bus needs to be released for wait states. This callback is REQUIRED for WAIT STATES. Raises: Exception: Implementations are free to raise any Exception. Exceptions are retained across the native boundary. """ pass tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/TSS2_Exception.py000066400000000000000000000040511506405471500223030ustar00rootroot00000000000000from ._libtpm2_pytss import lib, ffi from typing import Union class TSS2_Exception(RuntimeError): """TSS2_Exception represents an error returned by the TSS APIs.""" # prevent cirular dependency and don't use the types directly here. def __init__(self, rc: Union["TSS2_RC", "TPM2_RC", int]): if isinstance(rc, int): # defer this to avoid circular dep. from .constants import TSS2_RC rc = TSS2_RC(rc) errmsg = ffi.string(lib.Tss2_RC_Decode(rc)).decode() super(TSS2_Exception, self).__init__(f"{errmsg}") self._rc = rc self._handle = 0 self._parameter = 0 self._session = 0 self._error = 0 if self._rc & lib.TPM2_RC_FMT1: self._parse_fmt1() else: self._error = self._rc def _parse_fmt1(self): self._error = lib.TPM2_RC_FMT1 + (self.rc & 0x3F) if self.rc & lib.TPM2_RC_P: self._parameter = (self.rc & lib.TPM2_RC_N_MASK) >> 8 elif self.rc & lib.TPM2_RC_S: self._session = ((self.rc - lib.TPM2_RC_S) & lib.TPM2_RC_N_MASK) >> 8 else: self._handle = (self.rc & lib.TPM2_RC_N_MASK) >> 8 @property def rc(self): """int: The return code from the API call.""" return self._rc @property def handle(self): """int: The handle related to the error, 0 if not related to any handle.""" return self._handle @property def parameter(self): """int: The parameter related to the error, 0 if not related to any parameter.""" return self._parameter @property def session(self): """int: The session related to the error, 0 if not related to any session.""" return self._session @property def error(self): """int: The error with handle, parameter and session stripped.""" return self._error @property def fmt1(self): """bool: True if the error is related to a handle, parameter or session.""" return bool(self._rc & lib.TPM2_RC_FMT1) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/__init__.py000066400000000000000000000017671506405471500213040ustar00rootroot00000000000000import _cffi_backend # noqa: F401 # check that we can load the C bindings, # if we can't, provide a better message. try: from ._libtpm2_pytss import lib # noqa: F401 except ImportError as e: parts = e.msg.split(": ", 2) if len(parts) != 3: raise e path, error, symbol = parts if error != "undefined symbol": raise e raise ImportError( f"failed to load tpm2-tss bindigs in {path} due to missing symbol {symbol}, " + "ensure that you are using the same libraries the python module was built against." ) from .ESAPI import ESAPI # noqa: F401 try: from .FAPI import * except NotImplementedError: # Built on a system lacking FAPI, ignore pass try: from .policy import * except NotImplementedError: # Built on a system lacking libpolicy, ignore pass from .TCTILdr import * from .TCTI import TCTI, PyTCTI, PollData # noqa: F401 from .types import * from .constants import * from .TSS2_Exception import TSS2_Exception # noqa: F401 tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/command_parser.py000066400000000000000000001763361506405471500225440ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 import io from dataclasses import dataclass, fields from typing import ( Sequence, ClassVar, Optional, get_args, cast, Union, TypeVar, Generic, get_origin, ) from .constants import ( TPM2_ST, TPM2_CC, TPMA_SESSION, TPM2_RC, TPM2_SU, TPMI_YES_NO, TPM2_SE, TPM2_ALG, TPM2_RH, TPM2_ECC, TPMA_LOCALITY, TPM2_EO, TPM2_CAP, TPM2_CLOCK, TPM_AT, TSS2_RC, TPM_FRIENDLY_INT, TPM_INT_MU, ) from .types import ( TPM2_HANDLE, TPM2B_NONCE, TPM2B_AUTH, TPM2B_DIGEST, TPML_ALG, TPM2B_MAX_BUFFER, TPM2B_ENCRYPTED_SECRET, TPMT_SYM_DEF, TPM2B_SENSITIVE_CREATE, TPM2B_PUBLIC, TPM2B_DATA, TPML_PCR_SELECTION, TPM2B_PRIVATE, TPM2B_CREATION_DATA, TPMT_TK_CREATION, TPM2B_NAME, TPM2B_SENSITIVE, TPM2B_ID_OBJECT, TPM2B_SENSITIVE_DATA, TPM2B_TEMPLATE, TPMT_SYM_DEF_OBJECT, TPM2B_PUBLIC_KEY_RSA, TPMT_RSA_DECRYPT, TPM2B_ECC_POINT, TPMS_ALGORITHM_DETAIL_ECC, TPMT_KDF_SCHEME, TPM2B_IV, TPMT_TK_HASHCHECK, TPML_DIGEST_VALUES, TPMT_SIG_SCHEME, TPM2B_ATTEST, TPMT_SIGNATURE, TPMT_TK_VERIFIED, TPML_CC, TPM2B_EVENT, TPML_DIGEST, TPM2B_TIMEOUT, TPMT_TK_AUTH, TPM2B_OPERAND, TPMT_HA, TPMS_CONTEXT, TPMS_CAPABILITY_DATA, TPMT_PUBLIC_PARMS, TPM2B_NV_PUBLIC, TPM2B_MAX_NV_BUFFER, TPML_AC_CAPABILITIES, TPMS_AC_OUTPUT, TPM_OBJECT, TPM2B_SIMPLE_OBJECT, ) from .TSS2_Exception import TSS2_Exception TPM2_HEADER_SIZE = 10 class UINT16(int, TPM_INT_MU): """Represents an unsigned 16-bit integer.""" pass class UINT32(int, TPM_INT_MU): """Represents an unsigned 32-bit integer.""" pass class INT32(int, TPM_INT_MU): """Represents a signed 32-bit integer.""" pass class UINT64(int, TPM_INT_MU): """Represents a 64-bit integer.""" pass TPM2B_TYPES_ALIAS = Union[ TPM2B_SIMPLE_OBJECT, TPM2B_CREATION_DATA, TPM2B_ECC_POINT, TPM2B_NV_PUBLIC, TPM2B_PUBLIC, TPM2B_SENSITIVE, TPM2B_SENSITIVE_CREATE, TPM2B_TIMEOUT, ] T = TypeVar("T", bound=TPM2B_TYPES_ALIAS) class TPM_ENCRYPTED_PARAMETER(Generic[T]): """Encrypted parameter wrapper. Wraps an encrypted TPM2B parameter. Args: underlying_type (TPM2B_TYPES_ALIAS): The underlying TPM2B type. value (bytes): The encrypted buffer. Attributes: underlying_type (TPM2B_TYPES_ALIAS): The underlying TPM2B type. """ def __init__(self, underlying_type: type[T], value: bytes): self._type = underlying_type self._value = value @classmethod def unmarshal( cls, underlying_type: type[T], buf: bytes ) -> tuple["TPM_ENCRYPTED_PARAMETER[T]", int]: size = int.from_bytes(buf[0:2], byteorder="big") buf = buf[2:] value = buf[:size] off = 2 + size return cls(underlying_type, value), off def marshal(self) -> bytes: size_bytes = len(self._value).to_bytes(2, byteorder="big") return size_bytes + self._value @property def underlying_type(self): return self._type def __bytes__(self) -> bytes: return self._value def __eq__(self, other: object) -> bool: if isinstance(other, bytes): return other == self._value elif hasattr(other, "__bytes__"): return bytes(other) == self._value return False TPM2_TYPES_ALIAS = Union[ TPM_INT_MU, TPM_FRIENDLY_INT, TPM_OBJECT, TPM2_HANDLE, TPM_ENCRYPTED_PARAMETER, ] @dataclass class tpm2_command_session: """Represents a command session.""" handle: TPM2_HANDLE nonce: TPM2B_NONCE attributes: TPMA_SESSION authorization: TPM2B_AUTH @dataclass class tpm2_response_session: """Represents a response session.""" nonce: TPM2B_NONCE attributes: TPMA_SESSION acknowledgment: TPM2B_DIGEST @dataclass class tpm2_command: """Represents a TPM2 command. Attributes: tag (TPM2_ST): Either `TPM2_ST.SESSIONS` or `TPM2_ST.NO_SESSIONS`. command_code (TPM2_CC): The command code. handles (Sequence[TPM2_HANDLE]): The handles for the command. parameters (Sequence[TPM2_TYPES_ALIAS]): The parameters for the command. session (Sequence[tpm2_command_session]): The sessions included in the command. """ tag: TPM2_ST command_code: ClassVar[TPM2_CC] handles: Sequence[TPM2_HANDLE] parameters: Sequence[TPM2_TYPES_ALIAS] sessions: Sequence[tpm2_command_session] _commands_: ClassVar[dict[TPM2_CC, type["tpm2_command"]]] = dict() def __init_subclass__(cls): tpm2_command._commands_[cls.command_code] = cls @classmethod def lookup_command_class(cls, command_code: TPM2_CC) -> type["tpm2_command"]: if command_code not in tpm2_command._commands_: raise TSS2_Exception(TSS2_RC.BASE_RC_NOT_IMPLEMENTED) return tpm2_command._commands_[command_code] @classmethod def num_handles(cls) -> int: """The number of handles for command.""" for field in fields(cls): args = get_args(field.type) if field.name == "handles": return len(args) raise AttributeError(f"{cls.__name__} does not have the handles attribute") @classmethod def parameter_types(cls) -> Sequence[type[TPM2_TYPES_ALIAS]]: """The command parameter types.""" for field in fields(cls): args = get_args(field.type) if field.name == "parameters": return args raise AttributeError(f"{cls.__name__} does not have the parameters attribute") @dataclass class tpm2_response: """Represents a TPM2 response. Attributes: tag (TPM2_ST): Either `TPM2_ST.SESSIONS` or `TPM2_ST.NO_SESSIONS`. command_code (TPM2_CC): The command code matching the response. response_code (TPM2_RC): The response code. handle (Optional[TPM2_HANDLE]): The response handle, might be None. parameters (Sequence[TPM2_TYPES_ALIAS]): The response parameters. session (Sequence[tpm2_response_session]): The sessions included in the response. """ tag: TPM2_ST command_code: ClassVar[TPM2_CC] response_code: TPM2_RC handle: Optional[TPM2_HANDLE] parameters: Sequence[TPM2_TYPES_ALIAS] sessions: Sequence[tpm2_response_session] _commands_: ClassVar[dict[TPM2_CC, type["tpm2_response"]]] = dict() def __init_subclass__(cls): tpm2_response._commands_[cls.command_code] = cls @classmethod def lookup_response_class(cls, command_code: TPM2_CC) -> type["tpm2_response"]: if command_code not in tpm2_response._commands_: raise TSS2_Exception(TSS2_RC.BASE_RC_NOT_IMPLEMENTED) return tpm2_response._commands_[command_code] @classmethod def has_handle(cls) -> bool: """True if the response type contains a handle, else False.""" for field in fields(cls): if field.name == "handle" and field.type == TPM2_HANDLE: return True return False @classmethod def parameter_types(cls) -> Sequence[type[TPM2_TYPES_ALIAS]]: """The response parameter types.""" for field in fields(cls): args = get_args(field.type) if field.name == "parameters": return args raise AttributeError(f"{cls.__name__} does not have the parameters attribute") @dataclass class tpm2_startup_command(tpm2_command): command_code = TPM2_CC.Startup handles: tuple[()] parameters: tuple[TPM2_SU] @dataclass class tpm2_startup_response(tpm2_response): command_code = TPM2_CC.Startup handle: None parameters: tuple[()] @dataclass class tpm2_shutdown_command(tpm2_command): command_code = TPM2_CC.Shutdown handles: tuple[()] parameters: tuple[TPM2_SU] @dataclass class tpm2_shutdown_response(tpm2_response): command_code = TPM2_CC.Shutdown handle: None parameters: tuple[()] @dataclass class tpm2_selftest_command(tpm2_command): command_code = TPM2_CC.SelfTest handles: tuple[()] parameters: tuple[TPMI_YES_NO] @dataclass class tpm2_selftest_response(tpm2_response): command_code = TPM2_CC.SelfTest handle: None parameters: tuple[()] @dataclass class tpm2_incremental_selftest_command(tpm2_command): command_code = TPM2_CC.IncrementalSelfTest handles: tuple[()] parameters: tuple[TPML_ALG] @dataclass class tpm2_incremental_selftest_response(tpm2_response): command_code = TPM2_CC.IncrementalSelfTest handle: None parameters: tuple[TPML_ALG] @dataclass class tpm2_get_test_result_command(tpm2_command): command_code = TPM2_CC.GetTestResult handles: tuple[()] parameters: tuple[()] @dataclass class tpm2_get_test_result_response(tpm2_response): command_code = TPM2_CC.GetTestResult handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2_RC ] @dataclass class tpm2_start_auth_session_command(tpm2_command): command_code = TPM2_CC.StartAuthSession handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_NONCE, TPM_ENCRYPTED_PARAMETER[TPM2B_NONCE]], TPM2B_ENCRYPTED_SECRET, TPM2_SE, TPMT_SYM_DEF, TPM2_ALG, ] @dataclass class tpm2_start_auth_session_response(tpm2_response): command_code = TPM2_CC.StartAuthSession handle: TPM2_HANDLE parameters: tuple[Union[TPM2B_NONCE, TPM_ENCRYPTED_PARAMETER[TPM2B_NONCE]]] @dataclass class tpm2_policy_restart_command(tpm2_command): command_code = TPM2_CC.PolicyRestart handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_restart_response(tpm2_response): command_code = TPM2_CC.PolicyRestart handle: None parameters: tuple[()] @dataclass class tpm2_create_command(tpm2_command): command_code = TPM2_CC.Create handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_SENSITIVE_CREATE, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE_CREATE]], TPM2B_PUBLIC, TPM2B_DATA, TPML_PCR_SELECTION, ] @dataclass class tpm2_create_response(tpm2_response): command_code = TPM2_CC.Create handle: None parameters: tuple[ Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]], TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION, ] @dataclass class tpm2_load_command(tpm2_command): command_code = TPM2_CC.Load handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]], TPM2B_PUBLIC ] @dataclass class tpm2_load_response(tpm2_response): command_code = TPM2_CC.Load handle: TPM2_HANDLE parameters: tuple[Union[TPM2B_NAME, TPM_ENCRYPTED_PARAMETER[TPM2B_NAME]]] @dataclass class tpm2_load_external_command(tpm2_command): command_code = TPM2_CC.LoadExternal handles: tuple[()] parameters: tuple[ Union[TPM2B_SENSITIVE, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE]], TPM2B_PUBLIC, TPM2_RH, ] @dataclass class tpm2_load_external_response(tpm2_response): command_code = TPM2_CC.LoadExternal handle: TPM2_HANDLE parameters: tuple[Union[TPM2B_NAME, TPM_ENCRYPTED_PARAMETER[TPM2B_NAME]]] @dataclass class tpm2_read_public_command(tpm2_command): command_code = TPM2_CC.ReadPublic handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_read_public_response(tpm2_response): command_code = TPM2_CC.ReadPublic handle: None parameters: tuple[ Union[TPM2B_PUBLIC, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC]], TPM2B_NAME, TPM2B_NAME, ] @dataclass class tpm2_activate_credential_command(tpm2_command): command_code = TPM2_CC.ActivateCredential handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_ID_OBJECT, TPM_ENCRYPTED_PARAMETER[TPM2B_ID_OBJECT]], TPM2B_ENCRYPTED_SECRET, ] @dataclass class tpm2_activate_credential_response(tpm2_response): command_code = TPM2_CC.ActivateCredential handle: None parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_make_credential_command(tpm2_command): command_code = TPM2_CC.MakeCredential handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPM2B_NAME ] @dataclass class tpm2_make_credential_response(tpm2_response): command_code = TPM2_CC.MakeCredential handle: None parameters: tuple[ Union[TPM2B_ID_OBJECT, TPM_ENCRYPTED_PARAMETER[TPM2B_ID_OBJECT]], TPM2B_ENCRYPTED_SECRET, ] @dataclass class tpm2_unseal_command(tpm2_command): command_code = TPM2_CC.Unseal handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_unseal_response(tpm2_response): command_code = TPM2_CC.Unseal handle: None parameters: tuple[ Union[TPM2B_SENSITIVE_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE_DATA]] ] @dataclass class tpm2_object_change_auth_command(tpm2_command): command_code = TPM2_CC.ObjectChangeAuth handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]]] @dataclass class tpm2_object_change_auth_response(tpm2_response): command_code = TPM2_CC.ObjectChangeAuth handle: None parameters: tuple[Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]]] @dataclass class tpm2_create_loaded_command(tpm2_command): command_code = TPM2_CC.CreateLoaded handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_SENSITIVE_CREATE, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE_CREATE]], TPM2B_TEMPLATE, ] @dataclass class tpm2_create_loaded_response(tpm2_response): command_code = TPM2_CC.CreateLoaded handle: TPM2_HANDLE parameters: tuple[ Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]], TPM2B_PUBLIC, TPM2B_NAME, ] @dataclass class tpm2_duplicate_command(tpm2_command): command_code = TPM2_CC.Duplicate handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SYM_DEF_OBJECT ] @dataclass class tpm2_duplicate_response(tpm2_response): command_code = TPM2_CC.Duplicate handle: None parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET, ] @dataclass class tpm2_rewrap_command(tpm2_command): command_code = TPM2_CC.Rewrap handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]], TPM2B_NAME, TPM2B_ENCRYPTED_SECRET, ] @dataclass class tpm2_rewrap_response(tpm2_response): command_code = TPM2_CC.Rewrap handle: None parameters: tuple[ Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]], TPM2B_ENCRYPTED_SECRET, ] @dataclass class tpm2_import_command(tpm2_command): command_code = TPM2_CC.Import handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPM2B_PUBLIC, TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET, TPMT_SYM_DEF_OBJECT, ] @dataclass class tpm2_import_response(tpm2_response): command_code = TPM2_CC.Import handle: None parameters: tuple[Union[TPM2B_PRIVATE, TPM_ENCRYPTED_PARAMETER[TPM2B_PRIVATE]]] @dataclass class tpm2_rsa_encrypt_command(tpm2_command): command_code = TPM2_CC.RSA_Encrypt handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_PUBLIC_KEY_RSA, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC_KEY_RSA]], TPMT_RSA_DECRYPT, TPM2B_DATA, ] @dataclass class tpm2_rsa_encrypt_response(tpm2_response): command_code = TPM2_CC.RSA_Encrypt handle: None parameters: tuple[ Union[TPM2B_PUBLIC_KEY_RSA, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC_KEY_RSA]] ] @dataclass class tpm2_rsa_decrypt_command(tpm2_command): command_code = TPM2_CC.RSA_Decrypt handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_PUBLIC_KEY_RSA, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC_KEY_RSA]], TPMT_RSA_DECRYPT, TPM2B_DATA, ] @dataclass class tpm2_rsa_decrypt_response(tpm2_response): command_code = TPM2_CC.RSA_Decrypt handle: None parameters: tuple[ Union[TPM2B_PUBLIC_KEY_RSA, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC_KEY_RSA]] ] @dataclass class tpm2_ecdh_keygen_command(tpm2_command): command_code = TPM2_CC.ECDH_KeyGen handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_ecdh_keygen_response(tpm2_response): command_code = TPM2_CC.ECDH_KeyGen handle: None parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_ECC_POINT, ] @dataclass class tpm2_ecdh_zgen_command(tpm2_command): command_code = TPM2_CC.ECDH_ZGen handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]]] @dataclass class tpm2_ecdh_zgen_response(tpm2_response): command_code = TPM2_CC.ECDH_ZGen handle: None parameters: tuple[Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]]] @dataclass class tpm2_ecc_parameters_command(tpm2_command): command_code = TPM2_CC.ECC_Parameters handles: tuple[()] parameters: tuple[TPM2_ECC] @dataclass class tpm2_ecc_parameters_response(tpm2_response): command_code = TPM2_CC.ECC_Parameters handle: None parameters: tuple[TPMS_ALGORITHM_DETAIL_ECC] @dataclass class tpm2_zgen_2phase_command(tpm2_command): command_code = TPM2_CC.ZGen_2Phase handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_ECC_POINT, TPM2_ALG, UINT16, ] @dataclass class tpm2_zgen_2phase_response(tpm2_response): command_code = TPM2_CC.ZGen_2Phase handle: None parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_ECC_POINT, ] @dataclass class tpm2_ecc_encrypt_command(tpm2_command): command_code = TPM2_CC.ECC_Encrypt handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPMT_KDF_SCHEME, ] @dataclass class tpm2_ecc_encrypt_response(tpm2_response): command_code = TPM2_CC.ECC_Encrypt handle: None parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_MAX_BUFFER, TPM2B_DIGEST, ] @dataclass class tpm2_ecc_decrypt_command(tpm2_command): command_code = TPM2_CC.ECC_Decrypt handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_MAX_BUFFER, TPM2B_DIGEST, TPMT_KDF_SCHEME, ] @dataclass class tpm2_ecc_decrypt_response(tpm2_response): command_code = TPM2_CC.ECC_Decrypt handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_encrypt_decrypt_command(tpm2_command): command_code = TPM2_CC.EncryptDecrypt handles: tuple[TPM2_HANDLE] parameters: tuple[TPMI_YES_NO, TPM2_ALG, TPM2B_IV, TPM2B_MAX_BUFFER] @dataclass class tpm2_encrypt_decrypt_response(tpm2_response): command_code = TPM2_CC.EncryptDecrypt handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2B_IV ] @dataclass class tpm2_encrypt_decrypt2_command(tpm2_command): command_code = TPM2_CC.EncryptDecrypt2 handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPMI_YES_NO, TPM2_ALG, TPM2B_IV, ] @dataclass class tpm2_encrypt_decrypt2_response(tpm2_response): command_code = TPM2_CC.EncryptDecrypt2 handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2B_IV ] @dataclass class tpm2_hash_command(tpm2_command): command_code = TPM2_CC.Hash handles: tuple[()] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2_ALG, TPM2_RH, ] @dataclass class tpm2_hash_response(tpm2_response): command_code = TPM2_CC.Hash handle: None parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPMT_TK_HASHCHECK ] @dataclass class tpm2_mac_command(tpm2_command): # this covers the hmac command as well command_code = TPM2_CC.MAC handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2_ALG ] @dataclass class tpm2_mac_response(tpm2_response): command_code = TPM2_CC.MAC handle: None parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] # Reuse the MAC command/response classes as the HMAC and MAC command are the same tpm2_hmac_command = tpm2_mac_command tpm2_hmac_response = tpm2_mac_response @dataclass class tpm2_get_random_command(tpm2_command): command_code = TPM2_CC.GetRandom handles: tuple[()] parameters: tuple[UINT16] @dataclass class tpm2_get_random_response(tpm2_response): command_code = TPM2_CC.GetRandom handle: None parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_stir_random_command(tpm2_command): command_code = TPM2_CC.StirRandom handles: tuple[()] parameters: tuple[ Union[TPM2B_SENSITIVE_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE_DATA]] ] @dataclass class tpm2_stir_random_response(tpm2_response): command_code = TPM2_CC.StirRandom handle: None parameters: tuple[()] @dataclass class tpm2_mac_start_command(tpm2_command): # This covers HMAC_Start as well command_code = TPM2_CC.MAC_Start handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]], TPM2_ALG] @dataclass class tpm2_mac_start_response(tpm2_response): command_code = TPM2_CC.MAC_Start handle: TPM2_HANDLE parameters: tuple[()] # Reuse MAC start command/reponse for HMAC start as they are the same command tpm2_hmac_start_command = tpm2_mac_start_command tpm2_hmac_start_response = tpm2_mac_start_response @dataclass class tpm2_hash_sequence_start_command(tpm2_command): command_code = TPM2_CC.HashSequenceStart handles: tuple[()] parameters: tuple[Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]], TPM2_ALG] @dataclass class tpm2_hash_sequence_start_response(tpm2_response): command_code = TPM2_CC.HashSequenceStart handle: TPM2_HANDLE parameters: tuple[()] @dataclass class tpm2_sequence_update_command(tpm2_command): command_code = TPM2_CC.SequenceUpdate handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_sequence_update_response(tpm2_response): command_code = TPM2_CC.SequenceUpdate handle: None parameters: tuple[()] @dataclass class tpm2_sequence_complete_command(tpm2_command): command_code = TPM2_CC.SequenceComplete handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2_RH ] @dataclass class tpm2_sequence_complete_response(tpm2_response): command_code = TPM2_CC.SequenceComplete handle: None parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPMT_TK_HASHCHECK ] @dataclass class tpm2_event_sequence_complete_command(tpm2_command): command_code = TPM2_CC.EventSequenceComplete handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_event_sequence_complete_response(tpm2_response): command_code = TPM2_CC.EventSequenceComplete handle: None parameters: tuple[TPML_DIGEST_VALUES] @dataclass class tpm2_certify_command(tpm2_command): command_code = TPM2_CC.Certify handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME ] @dataclass class tpm2_certify_response(tpm2_response): command_code = TPM2_CC.Certify handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_certify_creation_command(tpm2_command): command_code = TPM2_CC.CertifyCreation handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPM2B_DIGEST, TPMT_SIG_SCHEME, TPMT_TK_CREATION, ] @dataclass class tpm2_certify_creation_response(tpm2_response): command_code = TPM2_CC.CertifyCreation handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_quote_command(tpm2_command): command_code = TPM2_CC.Quote handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME, TPML_PCR_SELECTION, ] @dataclass class tpm2_quote_response(tpm2_response): command_code = TPM2_CC.Quote handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_get_session_audit_digest_command(tpm2_command): command_code = TPM2_CC.GetSessionAuditDigest handles: tuple[TPM2_HANDLE, TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME ] @dataclass class tpm2_get_session_audit_digest_response(tpm2_response): command_code = TPM2_CC.GetSessionAuditDigest handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_get_command_audit_digest_command(tpm2_command): command_code = TPM2_CC.GetCommandAuditDigest handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME ] @dataclass class tpm2_get_command_audit_digest_response(tpm2_response): command_code = TPM2_CC.GetCommandAuditDigest handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_get_time_command(tpm2_command): command_code = TPM2_CC.GetTime handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME ] @dataclass class tpm2_get_time_response(tpm2_response): command_code = TPM2_CC.GetTime handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] @dataclass class tpm2_certify_x509_command(tpm2_command): command_code = TPM2_CC.CertifyX509 handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME, TPM2B_MAX_BUFFER, ] @dataclass class tpm2_certify_x509_response(tpm2_response): command_code = TPM2_CC.CertifyX509 handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], TPM2B_DIGEST, TPMT_SIGNATURE, ] @dataclass class tpm2_commit_command(tpm2_command): command_code = TPM2_CC.Commit handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_SENSITIVE_DATA, TPM2B_ECC_POINT, ] @dataclass class tpm2_commit_response(tpm2_response): command_code = TPM2_CC.Commit handle: None parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], TPM2B_ECC_POINT, TPM2B_ECC_POINT, UINT16, ] @dataclass class tpm2_ec_ephemeral_command(tpm2_command): command_code = TPM2_CC.EC_Ephemeral handles: tuple[()] parameters: tuple[TPM2_ECC] @dataclass class tpm2_ec_ephemeral_response(tpm2_response): command_code = TPM2_CC.EC_Ephemeral handle: None parameters: tuple[ Union[TPM2B_ECC_POINT, TPM_ENCRYPTED_PARAMETER[TPM2B_ECC_POINT]], UINT16 ] @dataclass class tpm2_verify_signature_command(tpm2_command): command_code = TPM2_CC.VerifySignature handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPMT_SIGNATURE ] @dataclass class tpm2_verify_signature_response(tpm2_response): command_code = TPM2_CC.VerifySignature handle: None parameters: tuple[TPMT_TK_VERIFIED] @dataclass class tpm2_sign_command(tpm2_command): command_code = TPM2_CC.Sign handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPMT_SIG_SCHEME, TPMT_TK_HASHCHECK, ] @dataclass class tpm2_sign_response(tpm2_response): command_code = TPM2_CC.Sign handle: None parameters: tuple[TPMT_SIGNATURE] @dataclass class tpm2_set_command_code_audit_status_command(tpm2_command): command_code = TPM2_CC.SetCommandCodeAuditStatus handles: tuple[TPM2_HANDLE] parameters: tuple[TPM2_ALG, TPML_CC, TPML_CC] @dataclass class tpm2_set_command_code_audit_status_response(tpm2_response): command_code = TPM2_CC.SetCommandCodeAuditStatus handle: None parameters: tuple[()] @dataclass class tpm2_pcr_extend_command(tpm2_command): command_code = TPM2_CC.PCR_Extend handles: tuple[TPM2_HANDLE] parameters: tuple[TPML_DIGEST_VALUES] @dataclass class tpm2_pcr_extend_response(tpm2_response): command_code = TPM2_CC.PCR_Extend handle: None parameters: tuple[()] @dataclass class tpm2_pcr_event_command(tpm2_command): command_code = TPM2_CC.PCR_Event handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_EVENT, TPM_ENCRYPTED_PARAMETER[TPM2B_EVENT]]] @dataclass class tpm2_pcr_event_response(tpm2_response): command_code = TPM2_CC.PCR_Event handle: None parameters: tuple[TPML_DIGEST_VALUES] @dataclass class tpm2_pcr_read_command(tpm2_command): command_code = TPM2_CC.PCR_Read handles: tuple[()] parameters: tuple[TPML_PCR_SELECTION] @dataclass class tpm2_pcr_read_response(tpm2_response): command_code = TPM2_CC.PCR_Read handle: None parameters: tuple[UINT32, TPML_PCR_SELECTION, TPML_DIGEST] @dataclass class tpm2_pcr_allocated_command(tpm2_command): command_code = TPM2_CC.PCR_Allocate handles: tuple[TPM2_HANDLE] parameters: tuple[TPML_PCR_SELECTION] @dataclass class tpm2_pcr_allocate_response(tpm2_response): command_code = TPM2_CC.PCR_Allocate handle: None parameters: tuple[TPMI_YES_NO, UINT32, UINT32, UINT32] @dataclass class tpm2_pcr_set_auth_policy_command(tpm2_command): command_code = TPM2_CC.PCR_SetAuthPolicy handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPM2_ALG, TPM2_RH ] @dataclass class tpm2_pcr_set_auth_policy_response(tpm2_response): command_code = TPM2_CC.PCR_SetAuthPolicy handle: None parameters: tuple[()] @dataclass class tpm2_pcr_set_auth_value_command(tpm2_command): command_code = TPM2_CC.PCR_SetAuthValue handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_pcr_set_auth_value_response(tpm2_response): command_code = TPM2_CC.PCR_SetAuthValue handle: None parameters: tuple[()] @dataclass class tpm2_pcr_reset_command(tpm2_command): command_code = TPM2_CC.PCR_Reset handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_pcr_reset_response(tpm2_response): command_code = TPM2_CC.PCR_Reset handle: None parameters: tuple[()] @dataclass class tpm2_policy_signed_command(tpm2_command): command_code = TPM2_CC.PolicySigned handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_NONCE, TPM_ENCRYPTED_PARAMETER[TPM2B_NONCE]], TPM2B_DIGEST, TPM2B_NONCE, INT32, TPMT_SIGNATURE, ] @dataclass class tpm2_policy_signed_response(tpm2_response): command_code = TPM2_CC.PolicySigned handle: None parameters: tuple[ Union[TPM2B_TIMEOUT, TPM_ENCRYPTED_PARAMETER[TPM2B_TIMEOUT]], TPMT_TK_AUTH ] @dataclass class tpm2_policy_secret_command(tpm2_command): command_code = TPM2_CC.PolicySecret handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_NONCE, TPM_ENCRYPTED_PARAMETER[TPM2B_NONCE]], TPM2B_DIGEST, TPM2B_NONCE, INT32, ] @dataclass class tpm2_policy_secret_response(tpm2_response): command_code = TPM2_CC.PolicySecret handle: None parameters: tuple[ Union[TPM2B_TIMEOUT, TPM_ENCRYPTED_PARAMETER[TPM2B_TIMEOUT]], TPMT_TK_AUTH ] @dataclass class tpm2_policy_ticket_command(tpm2_command): command_code = TPM2_CC.PolicyTicket handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_TIMEOUT, TPM_ENCRYPTED_PARAMETER[TPM2B_TIMEOUT]], TPM2B_DIGEST, TPM2B_NONCE, TPM2B_NAME, TPMT_TK_AUTH, ] @dataclass class tpm2_policy_ticket_response(tpm2_response): command_code = TPM2_CC.PolicyTicket handle: None parameters: tuple[()] @dataclass class tpm2_policy_or_command(tpm2_command): command_code = TPM2_CC.PolicyOR handles: tuple[TPM2_HANDLE] parameters: tuple[TPML_DIGEST] @dataclass class tpm2_policy_or_response(tpm2_response): command_code = TPM2_CC.PolicyOR handle: None parameters: tuple[()] @dataclass class tpm2_policy_pcr_command(tpm2_command): command_code = TPM2_CC.PolicyPCR handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_pcr_response(tpm2_response): command_code = TPM2_CC.PolicyPCR handle: None parameters: tuple[()] @dataclass class tpm2_policy_locality_command(tpm2_command): command_code = TPM2_CC.PolicyLocality handles: tuple[TPM2_HANDLE] parameters: tuple[TPMA_LOCALITY] @dataclass class tpm2_policy_locality_response(tpm2_response): command_code = TPM2_CC.PolicyLocality handle: None parameters: tuple[()] @dataclass class tpm2_policy_nv_command(tpm2_command): command_code = TPM2_CC.PolicyNV handles: tuple[TPM2_HANDLE, TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_OPERAND, TPM_ENCRYPTED_PARAMETER[TPM2B_OPERAND]], UINT16, TPM2_EO ] @dataclass class tpm2_policy_nv_response(tpm2_response): command_code = TPM2_CC.PolicyNV handle: None parameters: tuple[()] @dataclass class tpm2_policy_counter_timer_command(tpm2_command): command_code = TPM2_CC.PolicyCounterTimer handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_OPERAND, TPM_ENCRYPTED_PARAMETER[TPM2B_OPERAND]], UINT16, TPM2_EO ] @dataclass class tpm2_policy_counter_timer_response(tpm2_response): command_code = TPM2_CC.PolicyCounterTimer handle: None parameters: tuple[()] @dataclass class tpm2_command_code_command(tpm2_command): command_code = TPM2_CC.PolicyCommandCode handles: tuple[TPM2_HANDLE] parameters: tuple[TPM2_CC] @dataclass class tpm2_command_code_response(tpm2_response): command_code = TPM2_CC.PolicyCommandCode handle: None parameters: tuple[()] @dataclass class tpm2_policy_physical_presence_command(tpm2_command): command_code = TPM2_CC.PolicyPhysicalPresence handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_physical_presence_response(tpm2_response): command_code = TPM2_CC.PolicyPhysicalPresence handle: None parameters: tuple[()] @dataclass class tpm2_policy_cp_hash_command(tpm2_command): command_code = TPM2_CC.PolicyCpHash handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_cp_hash_response(tpm2_response): command_code = TPM2_CC.PolicyCpHash handle: None parameters: tuple[()] @dataclass class tpm2_policy_name_hash_command(tpm2_command): command_code = TPM2_CC.PolicyNameHash handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_name_hash_response(tpm2_response): command_code = TPM2_CC.PolicyNameHash handle: None parameters: tuple[()] @dataclass class tpm2_policy_duplication_select_command(tpm2_command): command_code = TPM2_CC.PolicyDuplicationSelect handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_NAME, TPM_ENCRYPTED_PARAMETER[TPM2B_NAME]], TPM2B_NAME, TPMI_YES_NO ] @dataclass class tpm2_policy_duplication_select_response(tpm2_response): command_code = TPM2_CC.PolicyDuplicationSelect handle: None parameters: tuple[()] @dataclass class tpm2_policy_authorize_command(tpm2_command): command_code = TPM2_CC.PolicyAuthorize handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPM2B_NONCE, TPM2B_NAME, TPMT_TK_VERIFIED, ] @dataclass class tpm2_policy_authorize_response(tpm2_response): command_code = TPM2_CC.PolicyAuthorize handle: None parameters: tuple[()] @dataclass class tpm2_policy_auth_value_command(tpm2_command): command_code = TPM2_CC.PolicyAuthValue handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_auth_value_response(tpm2_response): command_code = TPM2_CC.PolicyAuthValue handle: None parameters: tuple[()] @dataclass class tpm2_policy_password_command(tpm2_command): command_code = TPM2_CC.PolicyPassword handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_password_response(tpm2_response): command_code = TPM2_CC.PolicyPassword handle: None parameters: tuple[()] @dataclass class tpm2_policy_get_digest_command(tpm2_command): command_code = TPM2_CC.PolicyGetDigest handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_get_digest_response(tpm2_response): command_code = TPM2_CC.PolicyGetDigest handle: None parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_nv_written_command(tpm2_command): command_code = TPM2_CC.PolicyNvWritten handles: tuple[TPM2_HANDLE] parameters: tuple[TPMI_YES_NO] @dataclass class tpm2_policy_nv_written_response(tpm2_response): command_code = TPM2_CC.PolicyNvWritten handle: None parameters: tuple[()] @dataclass class tpm2_policy_template_command(tpm2_command): command_code = TPM2_CC.PolicyTemplate handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_template_response(tpm2_response): command_code = TPM2_CC.PolicyTemplate handle: None parameters: tuple[()] @dataclass class tpm2_policy_authorize_nv_command(tpm2_command): command_code = TPM2_CC.PolicyAuthorizeNV handles: tuple[TPM2_HANDLE, TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_policy_authorize_nv_response(tpm2_response): command_code = TPM2_CC.PolicyAuthorizeNV handle: None parameters: tuple[()] @dataclass class tpm2_policy_capability_command(tpm2_command): command_code = TPM2_CC.PolicyCapability handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_OPERAND, TPM_ENCRYPTED_PARAMETER[TPM2B_OPERAND]], UINT16, TPM2_EO, TPM2_CAP, UINT32, ] @dataclass class tpm2_policy_capability_response(tpm2_response): command_code = TPM2_CC.PolicyCapability handle: None parameters: tuple[()] @dataclass class tpm2_policy_parameters_command(tpm2_command): command_code = TPM2_CC.PolicyParameters handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]]] @dataclass class tpm2_policy_parameters_response(tpm2_response): command_code = TPM2_CC.PolicyParameters handle: None parameters: tuple[()] @dataclass class tpm2_create_primary_command(tpm2_command): command_code = TPM2_CC.CreatePrimary handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_SENSITIVE_CREATE, TPM_ENCRYPTED_PARAMETER[TPM2B_SENSITIVE_CREATE]], TPM2B_PUBLIC, TPM2B_DATA, TPML_PCR_SELECTION, ] @dataclass class tpm2_create_primary_response(tpm2_response): command_code = TPM2_CC.CreatePrimary handle: TPM2_HANDLE parameters: tuple[ Union[TPM2B_PUBLIC, TPM_ENCRYPTED_PARAMETER[TPM2B_PUBLIC]], TPM2B_CREATION_DATA, TPM2B_DIGEST, TPMT_TK_CREATION, TPM2B_NAME, ] @dataclass class tpm2_hierarchy_control_command(tpm2_command): command_code = TPM2_CC.HierarchyControl handles: tuple[TPM2_HANDLE] parameters: tuple[TPM2_RH, TPMI_YES_NO] @dataclass class tpm2_hierarchy_control_response(tpm2_response): command_code = TPM2_CC.HierarchyControl handle: None parameters: tuple[()] @dataclass class tpm2_set_primary_policy_command(tpm2_command): command_code = TPM2_CC.SetPrimaryPolicy handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPM2_ALG ] @dataclass class tpm2_set_primary_policy_response(tpm2_response): command_code = TPM2_CC.SetPrimaryPolicy handle: None parameters: tuple[()] @dataclass class tpm2_change_pps_command(tpm2_command): command_code = TPM2_CC.ChangePPS handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_change_pps_response(tpm2_response): command_code = TPM2_CC.ChangePPS handle: None parameters: tuple[()] @dataclass class tpm2_change_eps_command(tpm2_command): command_code = TPM2_CC.ChangeEPS handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_change_eps_response(tpm2_response): command_code = TPM2_CC.ChangeEPS handle: None parameters: tuple[()] @dataclass class tpm2_clear_command(tpm2_command): command_code = TPM2_CC.Clear handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_clear_response(tpm2_response): command_code = TPM2_CC.Clear handle: None parameters: tuple[()] @dataclass class tpm2_clear_control_command(tpm2_command): command_code = TPM2_CC.ClearControl handles: tuple[TPM2_HANDLE] parameters: tuple[TPMI_YES_NO] @dataclass class tpm2_clear_control_response(tpm2_response): command_code = TPM2_CC.ClearControl handle: None parameters: tuple[()] @dataclass class tpm2_hierarchy_change_auth_command(tpm2_command): command_code = TPM2_CC.HierarchyChangeAuth handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]]] @dataclass class tpm2_hierarchy_change_auth_response(tpm2_response): command_code = TPM2_CC.HierarchyChangeAuth handle: None parameters: tuple[()] @dataclass class tpm2_dictionary_attack_clock_reset_command(tpm2_command): command_code = TPM2_CC.DictionaryAttackLockReset handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_dictionary_attack_clock_reset_response(tpm2_response): command_code = TPM2_CC.DictionaryAttackLockReset handle: None parameters: tuple[()] @dataclass class tpm2_dictionary_attack_parameters_command(tpm2_command): command_code = TPM2_CC.DictionaryAttackParameters handles: tuple[TPM2_HANDLE] parameters: tuple[UINT32, UINT32, UINT32] @dataclass class tpm2_dictionary_attack_parameters_response(tpm2_response): command_code = TPM2_CC.DictionaryAttackParameters handle: None parameters: tuple[()] @dataclass class tpm2_pp_commands_command(tpm2_command): command_code = TPM2_CC.PP_Commands handles: tuple[TPM2_HANDLE] parameters: tuple[TPML_CC, TPML_CC] @dataclass class tpm2_pp_commands_response(tpm2_response): command_code = TPM2_CC.PP_Commands handle: None parameters: tuple[()] @dataclass class tpm2_set_algorithm_set_command(tpm2_command): command_code = TPM2_CC.SetAlgorithmSet handles: tuple[TPM2_HANDLE] parameters: tuple[UINT32] @dataclass class tpm2_set_algorithm_set_response(tpm2_response): command_code = TPM2_CC.SetAlgorithmSet handle: None parameters: tuple[()] @dataclass class tpm2_field_upgrade_start_command(tpm2_command): command_code = TPM2_CC.FieldUpgradeStart handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DIGEST, TPM_ENCRYPTED_PARAMETER[TPM2B_DIGEST]], TPMT_SIGNATURE ] @dataclass class tpm2_field_upgrade_start_response(tpm2_response): command_code = TPM2_CC.FieldUpgradeStart handle: None parameters: tuple[()] @dataclass class tpm2_field_upgrade_data_command(tpm2_command): command_code = TPM2_CC.FieldUpgradeData handles: tuple[()] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_field_upgrade_data_response(tpm2_response): command_code = TPM2_CC.FieldUpgradeData handle: None parameters: tuple[TPMT_HA, TPMT_HA] @dataclass class tpm2_firmware_read_command(tpm2_command): command_code = TPM2_CC.FirmwareRead handles: tuple[()] parameters: tuple[UINT32] @dataclass class tpm2_firmware_read_response(tpm2_response): command_code = TPM2_CC.FirmwareRead handle: None parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_context_save_command(tpm2_command): command_code = TPM2_CC.ContextSave handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_context_save_response(tpm2_response): command_code = TPM2_CC.ContextSave handle: None parameters: tuple[TPMS_CONTEXT] @dataclass class tpm2_context_load_command(tpm2_command): command_code = TPM2_CC.ContextLoad handles: tuple[()] parameters: tuple[TPMS_CONTEXT] @dataclass class tpm2_context_load_response(tpm2_response): command_code = TPM2_CC.ContextLoad handle: TPM2_HANDLE parameters: tuple[()] @dataclass class tpm2_flush_context_command(tpm2_command): command_code = TPM2_CC.FlushContext handles: tuple[()] parameters: tuple[TPM2_HANDLE] @dataclass class tpm2_flush_context_response(tpm2_response): command_code = TPM2_CC.FlushContext handle: None parameters: tuple[()] @dataclass class tpm2_evict_control_command(tpm2_command): command_code = TPM2_CC.EvictControl handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[TPM2_HANDLE] @dataclass class tpm2_evict_control_response(tpm2_response): command_code = TPM2_CC.EvictControl handle: None parameters: tuple[()] @dataclass class tpm2_read_clock_command(tpm2_command): command_code = TPM2_CC.ReadClock handles: tuple[()] parameters: tuple[()] @dataclass class tpm2_read_clock_response(tpm2_response): command_code = TPM2_CC.ReadClock handle: None parameters: tuple[()] @dataclass class tpm2_clock_set_command(tpm2_command): command_code = TPM2_CC.ClockSet handles: tuple[TPM2_HANDLE] parameters: tuple[UINT64] @dataclass class tpm2_clock_set_response(tpm2_response): command_code = TPM2_CC.ClockSet handle: None parameters: tuple[()] @dataclass class tpm2_clock_rate_adjust_command(tpm2_command): command_code = TPM2_CC.ClockRateAdjust handles: tuple[TPM2_HANDLE] parameters: tuple[TPM2_CLOCK] @dataclass class tpm2_clock_rate_adjust_response(tpm2_response): command_code = TPM2_CC.ClockRateAdjust handle: None parameters: tuple[()] @dataclass class tpm2_get_capability_command(tpm2_command): command_code = TPM2_CC.GetCapability handles: tuple[()] parameters: tuple[TPM2_CAP, UINT32, UINT32] @dataclass class tpm2_get_capability_response(tpm2_response): command_code = TPM2_CC.GetCapability handle: None parameters: tuple[TPMI_YES_NO, TPMS_CAPABILITY_DATA] @dataclass class tpm2_test_parms_command(tpm2_command): command_code = TPM2_CC.TestParms handles: tuple[()] parameters: tuple[TPMT_PUBLIC_PARMS] @dataclass class tpm2_test_parms_response(tpm2_response): command_code = TPM2_CC.TestParms handle: None parameters: tuple[()] # setcapability, missing structures @dataclass class tpm2_nv_define_space_command(tpm2_command): command_code = TPM2_CC.NV_DefineSpace handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]], TPM2B_NV_PUBLIC ] @dataclass class tpm2_nv_define_space_response(tpm2_response): command_code = TPM2_CC.NV_DefineSpace handle: None parameters: tuple[()] @dataclass class tpm2_nv_undefine_space_command(tpm2_command): command_code = TPM2_CC.NV_UndefineSpace handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_undefine_space_response(tpm2_response): command_code = TPM2_CC.NV_UndefineSpace handle: None parameters: tuple[()] @dataclass class tpm2_nv_undefine_space_special_command(tpm2_command): command_code = TPM2_CC.NV_UndefineSpaceSpecial handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_undefine_space_special_response(tpm2_response): command_code = TPM2_CC.NV_UndefineSpaceSpecial handle: None parameters: tuple[()] @dataclass class tpm2_nv_read_public_command(tpm2_command): command_code = TPM2_CC.NV_ReadPublic handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_read_public_response(tpm2_response): command_code = TPM2_CC.NV_ReadPublic handle: None parameters: tuple[ Union[TPM2B_NV_PUBLIC, TPM_ENCRYPTED_PARAMETER[TPM2B_NV_PUBLIC]], TPM2B_NAME ] @dataclass class tpm2_nv_write_command(tpm2_command): command_code = TPM2_CC.NV_Write handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]], UINT16 ] @dataclass class tpm2_nv_write_response(tpm2_response): command_code = TPM2_CC.NV_Write handle: None parameters: tuple[()] @dataclass class tpm2_nv_increment_command(tpm2_command): command_code = TPM2_CC.NV_Increment handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_increment_response(tpm2_response): command_code = TPM2_CC.NV_Increment handle: None parameters: tuple[()] @dataclass class tpm2_nv_extend_command(tpm2_command): command_code = TPM2_CC.NV_Extend handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_nv_extend_response(tpm2_response): command_code = TPM2_CC.NV_Extend handle: None parameters: tuple[()] @dataclass class tpm2_nv_set_bits_command(tpm2_command): command_code = TPM2_CC.NV_SetBits handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[UINT64] @dataclass class tpm2_nv_set_bits_response(tpm2_response): command_code = TPM2_CC.NV_SetBits handle: None parameters: tuple[()] @dataclass class tpm2_nv_write_lock_command(tpm2_command): command_code = TPM2_CC.NV_WriteLock handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_write_lock_response(tpm2_response): command_code = TPM2_CC.NV_WriteLock handle: None parameters: tuple[()] @dataclass class tpm2_nv_global_write_lock_command(tpm2_command): command_code = TPM2_CC.NV_GlobalWriteLock handles: tuple[TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_global_write_lock_response(tpm2_response): command_code = TPM2_CC.NV_GlobalWriteLock handle: None parameters: tuple[()] @dataclass class tpm2_nv_read_command(tpm2_command): command_code = TPM2_CC.NV_Read handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[UINT16, UINT16] @dataclass class tpm2_nv_read_response(tpm2_response): command_code = TPM2_CC.NV_Read handle: None parameters: tuple[ Union[TPM2B_MAX_NV_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_NV_BUFFER]] ] @dataclass class tpm2_nv_read_lock_command(tpm2_command): command_code = TPM2_CC.NV_ReadLock handles: tuple[TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[()] @dataclass class tpm2_nv_read_lock_response(tpm2_response): command_code = TPM2_CC.NV_ReadLock handle: None parameters: tuple[()] @dataclass class tpm2_nv_change_auth_command(tpm2_command): command_code = TPM2_CC.NV_ChangeAuth handles: tuple[TPM2_HANDLE] parameters: tuple[Union[TPM2B_AUTH, TPM_ENCRYPTED_PARAMETER[TPM2B_AUTH]]] @dataclass class tpm2_nv_change_auth_response(tpm2_response): command_code = TPM2_CC.NV_ChangeAuth handle: None parameters: tuple[()] @dataclass class tpm2_nv_certifiy_command(tpm2_command): command_code = TPM2_CC.NV_Certify handles: tuple[TPM2_HANDLE, TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_DATA, TPM_ENCRYPTED_PARAMETER[TPM2B_DATA]], TPMT_SIG_SCHEME, UINT16, UINT16, ] @dataclass class tpm2_nv_certifiy_response(tpm2_response): command_code = TPM2_CC.NV_Certify handle: None parameters: tuple[ Union[TPM2B_ATTEST, TPM_ENCRYPTED_PARAMETER[TPM2B_ATTEST]], TPMT_SIGNATURE ] # nv_definespace2, missing structure # nv_readpublic2, missing structures @dataclass class tpm2_ac_get_capability_command(tpm2_command): command_code = TPM2_CC.AC_GetCapability handles: tuple[TPM2_HANDLE] parameters: tuple[TPM_AT, UINT32] @dataclass class tpm2_ac_get_capability_response(tpm2_response): command_code = TPM2_CC.AC_GetCapability handle: None parameters: tuple[TPMI_YES_NO, TPML_AC_CAPABILITIES] @dataclass class tpm2_ac_send_command(tpm2_command): command_code = TPM2_CC.AC_Send handles: tuple[TPM2_HANDLE, TPM2_HANDLE, TPM2_HANDLE] parameters: tuple[ Union[TPM2B_MAX_BUFFER, TPM_ENCRYPTED_PARAMETER[TPM2B_MAX_BUFFER]] ] @dataclass class tpm2_ac_send_response(tpm2_response): command_code = TPM2_CC.AC_Send handle: None parameters: tuple[TPMS_AC_OUTPUT] @dataclass class tpm2_policy_ac_send_select_command(tpm2_command): command_code = TPM2_CC.Policy_AC_SendSelect handles: tuple[TPM2_HANDLE] parameters: tuple[ Union[TPM2B_NAME, TPM_ENCRYPTED_PARAMETER[TPM2B_NAME]], TPM2B_NAME, TPM2B_NAME, TPMI_YES_NO, ] @dataclass class tpm2_policy_ac_send_select_response(tpm2_response): command_code = TPM2_CC.Policy_AC_SendSelect handle: None parameters: tuple[()] @dataclass class tpm2_act_set_timeout_command(tpm2_command): command_code = TPM2_CC.ACT_SetTimeout handles: tuple[TPM2_HANDLE] parameters: tuple[UINT32] @dataclass class tpm2_act_set_timeout_response(tpm2_response): command_code = TPM2_CC.ACT_SetTimeout handle: None parameters: tuple[()] @dataclass class tpm2_vendor_tcg_test_command(tpm2_command): command_code = TPM2_CC.Vendor_TCG_Test handles: tuple[()] parameters: tuple[TPM2B_DATA] @dataclass class tpm2_vendor_tcg_test_response(tpm2_response): command_code = TPM2_CC.Vendor_TCG_Test handle: None parameters: tuple[TPM2B_DATA] def read_and_unmarshal( data: bytes, *args: type[TPM2_TYPES_ALIAS] ) -> tuple[Sequence[TPM2_TYPES_ALIAS], int]: """Read and unmarshal a sequence of TPM2 types. Args: data (bytes): The bytes to unmarshal. *args (type[TPM2_TYPES_ALIAS]): A sequence of TPM2 type classes to unmarshal with. Returns: A sequence of TPM2 types and the number of bytes unmarshaled. """ off = 0 values: list[TPM2_TYPES_ALIAS] = [] value: TPM2_TYPES_ALIAS for cls in args: origin = get_origin(cls) if origin: underlying_type = get_args(cls)[0] cls = origin if issubclass(cls, TPM_ENCRYPTED_PARAMETER): value, suboff = cls.unmarshal(underlying_type, data[off:]) else: value, suboff = cls.unmarshal(data[off:]) off += suboff values.append(value) return tuple(values), off def read_command_sessions(fp) -> Sequence[tpm2_command_session]: """Get the command sessions from a file-like object. Args: fp: A file-like object. Returns: A sequence containing `tpm2_command_session` """ size_data = fp.read(4) size = int.from_bytes(size_data, byteorder="big") data = fp.read(size) sessions: list[tpm2_command_session] = list() while len(data): (handle, nonce, attributes, authorization), off = read_and_unmarshal( data, TPM2_HANDLE, TPM2B_NONCE, TPMA_SESSION, TPM2B_AUTH ) handle = cast(TPM2_HANDLE, handle) nonce = cast(TPM2B_NONCE, nonce) attributes = cast(TPMA_SESSION, attributes) authorization = cast(TPM2B_AUTH, authorization) session = tpm2_command_session( handle=handle, nonce=nonce, attributes=attributes, authorization=authorization, ) sessions.append(session) data = data[off:] return tuple(sessions) def read_command_header(fp) -> tuple[TPM2_ST, TPM2_CC, int]: """Read the command header from a file-like object. Args: fp: A file-like object. Returns: A tuple containg the tag (TPM2_ST), command code (TPM2_RC) and the length (int) of the remaining command data. """ data = fp.read(TPM2_HEADER_SIZE) (tag, size, command_code), off = read_and_unmarshal(data, TPM2_ST, UINT32, TPM2_CC) tag = cast(TPM2_ST, tag) size = cast(UINT32, size) command_code = cast(TPM2_CC, command_code) left = size - off return tag, command_code, left def _set_encrypted_parameter( parameters: Sequence[type[TPM2_TYPES_ALIAS]], sessions: Sequence[Union[tpm2_command_session, tpm2_response_session]], session_flag: TPMA_SESSION, ) -> Sequence[type[TPM2_TYPES_ALIAS]]: if not parameters: return parameters args = get_args(parameters[0]) encrypted_type: Optional[type[TPM2_TYPES_ALIAS]] = None for arg in args: if get_origin(arg) == TPM_ENCRYPTED_PARAMETER: encrypted_type = arg if encrypted_type is None: return parameters has_flag = False for session in sessions: if session.attributes & session_flag: has_flag = True break if has_flag: first_param = encrypted_type else: first_param = get_args(encrypted_type)[0] return (first_param,) + tuple(parameters[1:]) def read_command(fp) -> tpm2_command: """Read a command from a file-like object. Args: fp: A file-like object. Returns: `tpm2_command` """ tag, cc, left = read_command_header(fp) data = fp.read(left) if tag not in (TPM2_ST.NO_SESSIONS, TPM2_ST.SESSIONS): raise TSS2_Exception(TPM2_RC.BAD_TAG) subfp = io.BytesIO(data) command = tpm2_command.lookup_command_class(cc) num_handles = command.num_handles() handles = [] for _ in range(0, num_handles): handle_data = subfp.read(4) handle, _ = TPM2_HANDLE.unmarshal(handle_data) handles.append(handle) sessions: Sequence[tpm2_command_session] = [] if tag == TPM2_ST.SESSIONS: sessions = read_command_sessions(subfp) parameters = command.parameter_types() parameters = _set_encrypted_parameter(parameters, sessions, TPMA_SESSION.DECRYPT) parameter_data = subfp.read() parameter_values, _ = read_and_unmarshal(parameter_data, *parameters) c = command( tag=tag, handles=handles, parameters=tuple(parameter_values), sessions=tuple(sessions), ) return c def read_response_sessions(fp) -> Sequence[tpm2_response_session]: """Get the response sessions from a file-like object. Args: fp: a file-like object. Returns: A sequence containing `tpm2_response_session` """ size_data = fp.read(4) size, _ = UINT32.unmarshal(size_data) data = fp.read(size) off = 0 sessions: list[tpm2_response_session] = [] while len(data): (nonce, attributes, acknowledgment), off = read_and_unmarshal( data, TPM2B_NONCE, TPMA_SESSION, TPM2B_DIGEST ) nonce = cast(TPM2B_NONCE, nonce) attributes = cast(TPMA_SESSION, attributes) acknowledgment = cast(TPM2B_DIGEST, acknowledgment) session = tpm2_response_session( nonce=nonce, attributes=attributes, acknowledgment=acknowledgment ) sessions.append(session) data = data[off:] return tuple(sessions) def read_response_header(fp) -> tuple[TPM2_ST, TPM2_RC, int]: """Read the response header from a file-like object. Args: fp: A file-like object. Returns: A tuple containg the tag (TPM2_ST), response code (TPM2_RC) and the length (int) of the remaining response data. """ data = fp.read(TPM2_HEADER_SIZE) (tag, size, response_code), off = read_and_unmarshal(data, TPM2_ST, UINT32, TPM2_RC) tag = cast(TPM2_ST, tag) size = cast(UINT32, size) response_code = cast(TPM2_RC, response_code) left = size - off return tag, response_code, left def read_response(fp, command_code: TPM2_CC) -> tpm2_response: """Read a response from a file-like object. Args: fp: A file-like object. command_code (TPM2_CC): The command code matching the command the response if for. Returns: `tpm2_response` """ tag, response_code, left = read_response_header(fp) data = fp.read(left) if tag not in (TPM2_ST.NO_SESSIONS, TPM2_ST.SESSIONS): raise TSS2_Exception(TPM2_RC.BAD_TAG) subfp = io.BytesIO(data) if response_code != TPM2_RC.SUCCESS: return tpm2_response( tag=tag, response_code=response_code, handle=None, parameters=tuple(), sessions=tuple(), ) response = tpm2_response.lookup_response_class(command_code) handle: Optional[TPM2_HANDLE] = None if response.has_handle(): handle_data = subfp.read(4) handle, _ = TPM2_HANDLE.unmarshal(handle_data) if tag == TPM2_ST.SESSIONS: parameter_size_data = subfp.read(4) parameter_size = int.from_bytes(parameter_size_data, byteorder="big") else: parameter_size = -1 parameters: Sequence[type[TPM2_TYPES_ALIAS]] = response.parameter_types() parameter_data = subfp.read(parameter_size) sessions: Sequence[tpm2_response_session] = [] if tag == TPM2_ST.SESSIONS: sessions = read_response_sessions(subfp) parameters = _set_encrypted_parameter(parameters, sessions, TPMA_SESSION.ENCRYPT) parameter_values, _ = read_and_unmarshal(parameter_data, *parameters) r = tpm2_response( tag=tag, response_code=response_code, handle=handle, parameters=tuple(parameter_values), sessions=tuple(sessions), ) return r tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/constants.py000066400000000000000000001437571506405471500215670ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 """ This module contains all the constant values from the following TCG specifications: - https://trustedcomputinggroup.org/resource/tpm-library-specification/. See Part 2 "Structures". - https://trustedcomputinggroup.org/resource/tss-overview-common-structures-specification Along with helpers to go from string values to constants and constant values to string values. """ from ._libtpm2_pytss import lib, ffi from .internal.utils import ( _CLASS_INT_ATTRS_from_string, _chkrc, ) import weakref class TPM_INT_MU: """Mixin class for marshaling/unmarshaling int types.""" def marshal(self): """Marshal instance into bytes. Returns: Returns the marshaled type as bytes. """ # use an alias name if set over the classname name = getattr(self, "_alias_name", self.__class__.__name__) mfunc = getattr(lib, f"Tss2_MU_{name}_Marshal", None) if mfunc is None: # default to scalar routines size = ffi.sizeof(f"{name}") * 8 mfunc = getattr(lib, f"Tss2_MU_UINT{size}_Marshal", None) if mfunc is None: raise RuntimeError( f"No marshal function found for {self.__class__.__name__}" ) size = ffi.sizeof(f"{name}") offset = ffi.new("size_t *") buf = ffi.new(f"uint8_t[{size}]") _chkrc(mfunc(int(self), buf, size, offset)) return bytes(buf[0 : offset[0]]) @classmethod def unmarshal(cls, buf): """Unmarshal bytes into type instance. Args: buf (bytes): The bytes to be unmarshaled. Returns: Returns an instance of the current type and the number of bytes consumed. """ # use an alias name if set over the classname name = getattr(cls, "_alias_name", cls.__name__) umfunc = getattr(lib, f"Tss2_MU_{name}_Unmarshal", None) if umfunc is None: # default to scalar routines size = ffi.sizeof(f"{name}") * 8 umfunc = getattr(lib, f"Tss2_MU_UINT{size}_Unmarshal", None) if umfunc is None: raise RuntimeError(f"No unmarshal function found for {cls.__name__}") cdata = ffi.new(f"{name} *") offset = ffi.new("size_t *") _chkrc(umfunc(buf, len(buf), offset, cdata)) return (cls(cdata[0]), offset[0]) class TPM_FRIENDLY_ITER(type): """Metaclass to make constants classes iterable""" def __iter__(cls): """Returns an iteratore over the constants in the class. Returns: (int): The int values of the constants in the class. Example: list(ESYS_TR) -> [4095, 255, 0, 1, 2, 3, ... ] """ for value in cls._members_.values(): yield value class TPM_FRIENDLY_INT(int, TPM_INT_MU, metaclass=TPM_FRIENDLY_ITER): _FIXUP_MAP = {} @staticmethod def _get_members(cls) -> dict: """Finds all constants defined at class level.""" members = dict() # Inherit constants from parent classes for sc in cls.__mro__[1:]: if not issubclass(sc, TPM_FRIENDLY_INT): break super_members = sc._get_members(sc) members.update(super_members) # Any class attribute that is an int and is not marked as private is a member for name, value in vars(cls).items(): if not isinstance(value, int) or name.startswith("_"): continue members[name] = value return members def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) members = TPM_FRIENDLY_INT._get_members(cls) # Ensure that the members of the constant class have the class as the type for name, value in members.items(): fixed_value = cls(value) members[name] = fixed_value setattr(cls, name, fixed_value) # Save the members so they can be used later cls._members_ = members @classmethod def parse(cls, value: str) -> int: # If it's a string initializer value, see if it matches anything in the list if isinstance(value, str): try: x = _CLASS_INT_ATTRS_from_string(cls, value, cls._FIXUP_MAP) if not isinstance(x, int): raise KeyError(f'Expected int got: "{type(x)}"') return x except KeyError: raise ValueError( f'Could not convert friendly name to value, got: "{value}"' ) else: raise TypeError(f'Expected value to be a str object, got: "{type(value)}"') @classmethod def __contains__(cls, value: int) -> bool: """Indicates if a class contains a numeric constant. Args: value (int): The raw numerical number to test for. Returns: (bool): True if the class contains the constant, False otherwise. Example: 7 in ESYS_TR -> True """ return value in cls._members_.values() @classmethod def to_string(cls, value: int) -> str: """Converts an integer value into it's friendly string name for that class. Args: value (int): The raw numerical number to try and convert to a name. Returns: (str): The string of the constant defining the raw numeric. Raises: ValueError: If the numeric does not match a constant. Example: ESYS_TR.to_string(5) -> 'ESYS_TR.PCR5' """ # Take the shortest match, ie OWNER over RH_OWNER. m = None items = vars(cls).items() for k, v in items: if v == value and (m is None or len(k) < len(m)): m = k if m is None: raise ValueError(f"Could not match {value} to class {cls.__name__}") return f"{cls.__name__}.{m}" def __str__(self) -> str: """Returns a string value of the constant normalized to lowercase. Returns: (str): a string value of the constant normalized to lowercase. Example: str(ESYS_TR.PCR2) -> 'pcr2' """ for k, v in vars(self.__class__).items(): if int(self) == v: return k.lower() return str(int(self)) def __abs__(self): return self.__class__(int(self).__abs__()) def __add__(self, value): return self.__class__(int(self).__add__(value)) def __and__(self, value): return self.__class__(int(self).__and__(value)) def __ceil__(self): return self.__class__(int(self).__ceil__()) def __divmod__(self, value): a, b = int(self).__divmod__(value) return self.__class__(a), self.__class__(b) def __floor__(self): return self.__class__(int(self).__floor__()) def __floordiv__(self, value): return self.__class__(int(self).__floordiv__(value)) def __invert__(self): return self.__class__(int(self).__invert__()) def __lshift__(self, value): return self.__class__(int(self).__lshift__(value)) def __mod__(self, value): return self.__class__(int(self).__mod__(value)) def __mul__(self, value): return self.__class__(int(self).__mul__(value)) def __neg__(self): return self.__class__(int(self).__neg__()) def __or__(self, value): return self.__class__(int(self).__or__(value)) def __pos__(self): return self.__class__(int(self).__pos__()) def __pow__(self, value, mod=None): return self.__class__(int(self).__pow__(value, mod)) def __radd__(self, value): return self.__class__(int(self).__radd__(value)) def __rand__(self, value): return self.__class__(int(self).__rand__(value)) def __rdivmod__(self, value): a, b = int(self).__rdivmod__(value) return self.__class__(a), self.__class__(b) def __rfloordiv__(self, value): return self.__class__(int(self).__rfloordiv__(value)) def __rlshift__(self, value): return self.__class__(int(self).__rlshift__(value)) def __rmod__(self, value): return self.__class__(int(self).__rmod__(value)) def __rmul__(self, value): return self.__class__(int(self).__rmul__(value)) def __ror__(self, value): return self.__class__(int(self).__ror__(value)) def __round__(self): return self.__class__(int(self).__round__()) def __rpow__(self, value, mod=None): return self.__class__(int(self).__rpow__(value, mod)) def __rrshift__(self, value): return self.__class__(int(self).__rrshift__(value)) def __rshift__(self, value): return self.__class__(int(self).__rshift__(value)) def __rsub__(self, value): return self.__class__(int(self).__rsub__(value)) def __rtruediv__(self, value): return self.__class__(int(self).__rtruediv__(value)) def __rxor__(self, value): return self.__class__(int(self).__rxor__(value)) def __sub__(self, value): return self.__class__(int(self).__sub__(value)) def __truediv__(self, value): return self.__class__(int(self).__truediv__(value)) def __xor__(self, value): return self.__class__(int(self).__xor__(value)) class TPMA_FRIENDLY_INTLIST(TPM_FRIENDLY_INT): _MASKS = tuple() @classmethod def parse(cls, value: str) -> int: """Converts a string of | separated constant values into it's integer value. Given a pipe "|" separated list of string constant values that represent the bitwise values returns the value itself. The value "" (empty string) returns a 0. Args: value (str): The string "bitwise" expression of the object or the empty string. Returns: The integer result. Raises: TypeError: If the value is not a str. ValueError: If a field portion of the str does not match a constant. Examples: TPMA_NV.parse("ppwrite|orderly|NO_DA") -> 0x6000001 TPMA_NV.parse("NO_DA") -> 0x2000000 """ intvalue = 0 if not isinstance(value, str): raise TypeError(f'Expected value to be a str, got: "{type(value)}"') hunks = value.split("|") if "|" in value else [value] for k in list(hunks): if "=" not in k: continue hname, hval = k.split("=", 1) v = int(hval, base=0) hunks.remove(k) found = False for mask, shift, name in cls._MASKS: if hname != name: continue mv = mask >> shift if v > mv: raise ValueError( f"value for {name} is to large, got 0x{v:x}, max is 0x{mv:x}" ) intvalue = intvalue | (v << shift) found = True break if not found: raise ValueError(f"unknown mask type {hname}") for k in hunks: try: intvalue |= _CLASS_INT_ATTRS_from_string(cls, k, cls._FIXUP_MAP) except KeyError: raise ValueError( f'Could not convert friendly name to value, got: "{k}"' ) return intvalue def __str__(self): """Given a constant, return the string bitwise representation. Each constant is seperated by the "|" (pipe) character. Returns: (str): a bitwise string value of the fields for the constant normalized to lowercase. Raises: ValueError: If their are unmatched bits in the constant value. Example: str(TPMA_NV(TPMA_NV.PPWRITE|TPMA_NV.ORDERLY|TPMA_NV.NO_DA)) -> 'ppwrite|noda|orderly' """ cv = int(self) ints = list() for k, v in vars(self.__class__).items(): if cv == 0: break if ( not isinstance(v, int) or k.startswith(("_", "_DEFAULT")) or k.endswith(("_MASK", "_SHIFT")) ): continue for fk, fv in self._FIXUP_MAP.items(): if k == fv: k = fk break if v == 0 or v & cv != v: continue ints.append(k.lower()) cv = cv ^ v for mask, shift, name in self._MASKS: if not cv & mask: continue v = (cv & mask) >> shift s = f"{name}=0x{v:x}" cv = cv ^ (cv & mask) ints.append(s) if cv: raise ValueError(f"unnmatched values left: 0x{cv:x}") return "|".join(ints) class TPM2_MAX(TPM_FRIENDLY_INT): DIGEST_BUFFER = 1024 NV_BUFFER_SIZE = 2048 PCRS = 32 ALG_LIST_SIZE = 128 CAP_CC = 256 CAP_BUFFER = 1024 CONTEXT_SIZE = 5120 class ESYS_TR(TPM_FRIENDLY_INT): """ESYS_TR is an ESAPI identifier representing a TPM resource To get the ESYS_TR identifier for a persistent handle, such as a NV area or a persistent key use :func:`tpm2_pytss.ESAPI.tr_from_tpmpublic` Can be used as a context manager to flush transient and session handles. """ NONE = 0xFFF PASSWORD = 0x0FF PCR0 = 0 PCR1 = 1 PCR2 = 2 PCR3 = 3 PCR4 = 4 PCR5 = 5 PCR6 = 6 PCR7 = 7 PCR8 = 8 PCR9 = 9 PCR10 = 10 PCR11 = 11 PCR12 = 12 PCR13 = 13 PCR14 = 14 PCR15 = 15 PCR16 = 16 PCR17 = 17 PCR18 = 18 PCR19 = 19 PCR20 = 20 PCR21 = 21 PCR22 = 22 PCR23 = 23 PCR24 = 24 PCR25 = 25 PCR26 = 26 PCR27 = 27 PCR28 = 28 PCR29 = 29 PCR30 = 30 PCR31 = 31 OWNER = 0x101 NULL = 0x107 LOCKOUT = 0x10A ENDORSEMENT = 0x10B PLATFORM = 0x10C PLATFORM_NV = 0x10D RH_OWNER = 0x101 RH_NULL = 0x107 RH_LOCKOUT = 0x10A RH_ENDORSEMENT = 0x10B RH_PLATFORM = 0x10C RH_PLATFORM_NV = 0x10D RH_FW_OWNER = 0x10E RH_FW_ENDORSEMENT = 0x10F RH_FW_PLATFORM = 0x110 RH_FW_NULL = 0x111 RH_SVN_OWNER_BASE = 0x1010000 RH_SVN_ENDORSEMENT_BASE = 0x1020000 RH_SVN_PLATFORM_BASE = 0x1030000 RH_SVN_NULL_BASE = 0x1040000 RH_ACT_0 = 0x120 RH_ACT_1 = 0x121 RH_ACT_2 = 0x122 RH_ACT_3 = 0x123 RH_ACT_4 = 0x124 RH_ACT_5 = 0x125 RH_ACT_6 = 0x126 RH_ACT_7 = 0x127 RH_ACT_8 = 0x128 RH_ACT_9 = 0x129 RH_ACT_A = 0x12A RH_ACT_B = 0x12B RH_ACT_C = 0x12C RH_ACT_D = 0x12D RH_ACT_E = 0x12E RH_ACT_F = 0x12F def __new__(cls, value: int, ectx: "ESAPI" = None): obj = super().__new__(cls, value) if ectx is not None and not ectx.is_closed(): obj._ectx_ref = weakref.ref(ectx) else: obj._ectx_ref = None return obj def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb) -> bool: if self._ectx_ref is None: return False ectx = self._ectx_ref() if ectx is None or ectx.is_closed(): return False handle = ectx.tr_get_tpm_handle(self) if (handle & TPM2_HR.RANGE_MASK) in ( TPM2_HR.TRANSIENT, TPM2_HR.HMAC_SESSION, TPM2_HR.POLICY_SESSION, ): ectx.flush_context(self) self._ectx_ref = None return False def marshal(self): raise NotImplementedError("Use serialize() instead") @classmethod def unmarshal(cls, buf): raise NotImplementedError("Use deserialize() instead") def serialize(self, ectx: "ESAPI") -> bytes: """Same as see tpm2_pytss.ESAPI.tr_serialize Args: ectx(ESAPI): The esapi context the ESYS_TR was created from. Returns: A byte array of the serialized ESYS_TR. """ return ectx.tr_serialize(self) @staticmethod def deserialize(ectx: "ESAPI", buffer: bytes) -> "ESYS_TR": """Same as see tpm2_pytss.ESAPI.tr_derialize Args: ectx(ESAPI): The esapi context to load the ESYS_TR on. Returns: An ESYS_TR representing the TPM object. """ return ectx.tr_deserialize(buffer) def get_name(self, ectx: "ESAPI") -> "TPM2B_NAME": """Same as see tpm2_pytss.ESAPI.tr_get_name Args: ectx(ESAPI): The esapi context to retrieve the object name from. Returns: A TPM2B_NAME object. """ return ectx.tr_get_name(self) def close(self, ectx: "ESAPI"): """Same as see tpm2_pytss.ESAPI.tr_close Args: ectx(ESAPI): The esapi context to close the ESYS_TR on. """ return ectx.tr_close(self) @staticmethod def parts_to_blob(handle: "TPM2_HANDLE", public: "TPM2B_PUBLIC") -> bytes: """Converts a persistent handle and public to a serialized ESYS_TR. Args: handle(TPM2_HANDLE): The PERSISTENT handle to convert. public(TPM2B_PUBLIC): The corresponding public for the handle. Returns: A SERIALIZED ESYS_TR that can be used with ESYS_TR.deserialize later. """ if (handle >> TPM2_HR.SHIFT) != TPM2_HT.PERSISTENT: raise ValueError("Expected a persistent handle, got: {handle:#x}") b = bytearray() b.extend(handle.to_bytes(4, byteorder="big")) b.extend(public.get_name().marshal()) b.extend(int(1).to_bytes(4, byteorder="big")) b.extend(public.marshal()) return bytes(b) class TPM2_RH(TPM_FRIENDLY_INT): FIRST = 0x40000000 SRK = 0x40000000 OWNER = 0x40000001 REVOKE = 0x40000002 TRANSPORT = 0x40000003 OPERATOR = 0x40000004 ADMIN = 0x40000005 EK = 0x40000006 NULL = 0x40000007 UNASSIGNED = 0x40000008 PW = 0x40000009 LOCKOUT = 0x4000000A ENDORSEMENT = 0x4000000B PLATFORM = 0x4000000C PLATFORM_NV = 0x4000000D FW_OWNER = 0x40000140 FW_ENDORSEMENT = 0x40000141 FW_PLATFORM = 0x40000142 FW_NULL = 0x40000143 SVN_OWNER_BASE = 0x40010000 SVN_ENDORSEMENT_BASE = 0x40020000 SVN_PLATFORM_BASE = 0x40030000 SVN_NULL_BASE = 0x40040000 ACT_0 = 0x40000110 ACT_1 = 0x40000111 ACT_2 = 0x40000112 ACT_3 = 0x40000113 ACT_4 = 0x40000114 ACT_5 = 0x40000115 ACT_6 = 0x40000116 ACT_7 = 0x40000117 ACT_8 = 0x40000118 ACT_9 = 0x40000119 ACT_A = 0x4000011A ACT_B = 0x4000011B ACT_C = 0x4000011C ACT_D = 0x4000011D ACT_E = 0x4000011E ACT_F = 0x4000011F LAST = 0x4004FFFF class TPM2_ALG(TPM_FRIENDLY_INT): _alias_name = "TPM2_ALG_ID" ERROR = 0x0000 RSA = 0x0001 TDES = 0x0003 SHA = 0x0004 SHA1 = 0x0004 HMAC = 0x0005 AES = 0x0006 MGF1 = 0x0007 KEYEDHASH = 0x0008 XOR = 0x000A SHA256 = 0x000B SHA384 = 0x000C SHA512 = 0x000D NULL = 0x0010 SM3_256 = 0x0012 SM4 = 0x0013 RSASSA = 0x0014 RSAES = 0x0015 RSAPSS = 0x0016 OAEP = 0x0017 ECDSA = 0x0018 ECDH = 0x0019 ECDAA = 0x001A SM2 = 0x001B ECSCHNORR = 0x001C ECMQV = 0x001D KDF1_SP800_56A = 0x0020 KDF2 = 0x0021 KDF1_SP800_108 = 0x0022 ECC = 0x0023 SYMCIPHER = 0x0025 CAMELLIA = 0x0026 CTR = 0x0040 SHA3_256 = 0x0027 SHA3_384 = 0x0028 SHA3_512 = 0x0029 OFB = 0x0041 CBC = 0x0042 CFB = 0x0043 ECB = 0x0044 FIRST = 0x0001 LAST = 0x0044 class TPM2_ALG_ID(TPM2_ALG): pass class TPM2_ECC(TPM_FRIENDLY_INT): NONE = 0x0000 NIST_P192 = 0x0001 NIST_P224 = 0x0002 NIST_P256 = 0x0003 NIST_P384 = 0x0004 NIST_P521 = 0x0005 BN_P256 = 0x0010 BN_P638 = 0x0011 SM2_P256 = 0x0020 _FIXUP_MAP = { "192": "NIST_P192", "224": "NIST_P224", "256": "NIST_P256", "384": "NIST_P384", "521": "NIST_P521", "SM2": "SM2_P256", } class TPM2_ECC_CURVE(TPM2_ECC): pass class TPM2_CC(TPM_FRIENDLY_INT): NV_UndefineSpaceSpecial = 0x0000011F FIRST = 0x0000011F EvictControl = 0x00000120 HierarchyControl = 0x00000121 NV_UndefineSpace = 0x00000122 ChangeEPS = 0x00000124 ChangePPS = 0x00000125 Clear = 0x00000126 ClearControl = 0x00000127 ClockSet = 0x00000128 HierarchyChangeAuth = 0x00000129 NV_DefineSpace = 0x0000012A PCR_Allocate = 0x0000012B PCR_SetAuthPolicy = 0x0000012C PP_Commands = 0x0000012D SetPrimaryPolicy = 0x0000012E FieldUpgradeStart = 0x0000012F ClockRateAdjust = 0x00000130 CreatePrimary = 0x00000131 NV_GlobalWriteLock = 0x00000132 GetCommandAuditDigest = 0x00000133 NV_Increment = 0x00000134 NV_SetBits = 0x00000135 NV_Extend = 0x00000136 NV_Write = 0x00000137 NV_WriteLock = 0x00000138 DictionaryAttackLockReset = 0x00000139 DictionaryAttackParameters = 0x0000013A NV_ChangeAuth = 0x0000013B PCR_Event = 0x0000013C PCR_Reset = 0x0000013D SequenceComplete = 0x0000013E SetAlgorithmSet = 0x0000013F SetCommandCodeAuditStatus = 0x00000140 FieldUpgradeData = 0x00000141 IncrementalSelfTest = 0x00000142 SelfTest = 0x00000143 Startup = 0x00000144 Shutdown = 0x00000145 StirRandom = 0x00000146 ActivateCredential = 0x00000147 Certify = 0x00000148 PolicyNV = 0x00000149 CertifyCreation = 0x0000014A Duplicate = 0x0000014B GetTime = 0x0000014C GetSessionAuditDigest = 0x0000014D NV_Read = 0x0000014E NV_ReadLock = 0x0000014F ObjectChangeAuth = 0x00000150 PolicySecret = 0x00000151 Rewrap = 0x00000152 Create = 0x00000153 ECDH_ZGen = 0x00000154 HMAC = 0x00000155 MAC = 0x00000155 Import = 0x00000156 Load = 0x00000157 Quote = 0x00000158 RSA_Decrypt = 0x00000159 HMAC_Start = 0x0000015B MAC_Start = 0x0000015B SequenceUpdate = 0x0000015C Sign = 0x0000015D Unseal = 0x0000015E PolicySigned = 0x00000160 ContextLoad = 0x00000161 ContextSave = 0x00000162 ECDH_KeyGen = 0x00000163 EncryptDecrypt = 0x00000164 FlushContext = 0x00000165 LoadExternal = 0x00000167 MakeCredential = 0x00000168 NV_ReadPublic = 0x00000169 PolicyAuthorize = 0x0000016A PolicyAuthValue = 0x0000016B PolicyCommandCode = 0x0000016C PolicyCounterTimer = 0x0000016D PolicyCpHash = 0x0000016E PolicyLocality = 0x0000016F PolicyNameHash = 0x00000170 PolicyOR = 0x00000171 PolicyTicket = 0x00000172 ReadPublic = 0x00000173 RSA_Encrypt = 0x00000174 StartAuthSession = 0x00000176 VerifySignature = 0x00000177 ECC_Parameters = 0x00000178 FirmwareRead = 0x00000179 GetCapability = 0x0000017A GetRandom = 0x0000017B GetTestResult = 0x0000017C Hash = 0x0000017D PCR_Read = 0x0000017E PolicyPCR = 0x0000017F PolicyRestart = 0x00000180 ReadClock = 0x00000181 PCR_Extend = 0x00000182 PCR_SetAuthValue = 0x00000183 NV_Certify = 0x00000184 EventSequenceComplete = 0x00000185 HashSequenceStart = 0x00000186 PolicyPhysicalPresence = 0x00000187 PolicyDuplicationSelect = 0x00000188 PolicyGetDigest = 0x00000189 TestParms = 0x0000018A Commit = 0x0000018B PolicyPassword = 0x0000018C ZGen_2Phase = 0x0000018D EC_Ephemeral = 0x0000018E PolicyNvWritten = 0x0000018F PolicyTemplate = 0x00000190 CreateLoaded = 0x00000191 PolicyAuthorizeNV = 0x00000192 EncryptDecrypt2 = 0x00000193 AC_GetCapability = 0x00000194 AC_Send = 0x00000195 Policy_AC_SendSelect = 0x00000196 CertifyX509 = 0x00000197 ACT_SetTimeout = 0x00000198 ECC_Encrypt = 0x00000199 ECC_Decrypt = 0x0000019A PolicyCapability = 0x0000019B PolicyParameters = 0x0000019C LAST = 0x0000019C Vendor_TCG_Test = 0x20000000 class TPM2_SPEC(TPM_FRIENDLY_INT): FAMILY = 0x322E3000 LEVEL = 00 VERSION = 159 YEAR = 2019 DAY_OF_YEAR = 312 class TPM2_GENERATED(TPM_FRIENDLY_INT): VALUE = 0xFF544347 class TPM_BASE_RC(TPM_FRIENDLY_INT): def decode(self): return ffi.string(lib.Tss2_RC_Decode(self)).decode() class TPM2_RC(TPM_BASE_RC): SUCCESS = 0x000 BAD_TAG = 0x01E VER1 = 0x100 INITIALIZE = VER1 + 0x000 FAILURE = VER1 + 0x001 SEQUENCE = VER1 + 0x003 PRIVATE = VER1 + 0x00B HMAC = VER1 + 0x019 DISABLED = VER1 + 0x020 EXCLUSIVE = VER1 + 0x021 AUTH_TYPE = VER1 + 0x024 AUTH_MISSING = VER1 + 0x025 POLICY = VER1 + 0x026 PCR = VER1 + 0x027 PCR_CHANGED = VER1 + 0x028 UPGRADE = VER1 + 0x02D TOO_MANY_CONTEXTS = VER1 + 0x02E AUTH_UNAVAILABLE = VER1 + 0x02F REBOOT = VER1 + 0x030 UNBALANCED = VER1 + 0x031 COMMAND_SIZE = VER1 + 0x042 COMMAND_CODE = VER1 + 0x043 AUTHSIZE = VER1 + 0x044 AUTH_CONTEXT = VER1 + 0x045 NV_RANGE = VER1 + 0x046 NV_SIZE = VER1 + 0x047 NV_LOCKED = VER1 + 0x048 NV_AUTHORIZATION = VER1 + 0x049 NV_UNINITIALIZED = VER1 + 0x04A NV_SPACE = VER1 + 0x04B NV_DEFINED = VER1 + 0x04C BAD_CONTEXT = VER1 + 0x050 CPHASH = VER1 + 0x051 PARENT = VER1 + 0x052 NEEDS_TEST = VER1 + 0x053 NO_RESULT = VER1 + 0x054 SENSITIVE = VER1 + 0x055 MAX_FM0 = VER1 + 0x07F FMT1 = 0x080 ASYMMETRIC = FMT1 + 0x001 ATTRIBUTES = FMT1 + 0x002 HASH = FMT1 + 0x003 VALUE = FMT1 + 0x004 HIERARCHY = FMT1 + 0x005 KEY_SIZE = FMT1 + 0x007 MGF = FMT1 + 0x008 MODE = FMT1 + 0x009 TYPE = FMT1 + 0x00A HANDLE = FMT1 + 0x00B KDF = FMT1 + 0x00C RANGE = FMT1 + 0x00D AUTH_FAIL = FMT1 + 0x00E NONCE = FMT1 + 0x00F PP = FMT1 + 0x010 SCHEME = FMT1 + 0x012 SIZE = FMT1 + 0x015 SYMMETRIC = FMT1 + 0x016 TAG = FMT1 + 0x017 SELECTOR = FMT1 + 0x018 INSUFFICIENT = FMT1 + 0x01A SIGNATURE = FMT1 + 0x01B KEY = FMT1 + 0x01C POLICY_FAIL = FMT1 + 0x01D INTEGRITY = FMT1 + 0x01F TICKET = FMT1 + 0x020 BAD_AUTH = FMT1 + 0x022 EXPIRED = FMT1 + 0x023 POLICY_CC = FMT1 + 0x024 BINDING = FMT1 + 0x025 CURVE = FMT1 + 0x026 ECC_POINT = FMT1 + 0x027 FW_LIMITED = FMT1 + 0x028 SVN_LIMITED = FMT1 + 0x029 WARN = 0x900 CONTEXT_GAP = WARN + 0x001 OBJECT_MEMORY = WARN + 0x002 SESSION_MEMORY = WARN + 0x003 MEMORY = WARN + 0x004 SESSION_HANDLES = WARN + 0x005 OBJECT_HANDLES = WARN + 0x006 LOCALITY = WARN + 0x007 YIELDED = WARN + 0x008 CANCELED = WARN + 0x009 TESTING = WARN + 0x00A REFERENCE_H0 = WARN + 0x010 REFERENCE_H1 = WARN + 0x011 REFERENCE_H2 = WARN + 0x012 REFERENCE_H3 = WARN + 0x013 REFERENCE_H4 = WARN + 0x014 REFERENCE_H5 = WARN + 0x015 REFERENCE_H6 = WARN + 0x016 REFERENCE_S0 = WARN + 0x018 REFERENCE_S1 = WARN + 0x019 REFERENCE_S2 = WARN + 0x01A REFERENCE_S3 = WARN + 0x01B REFERENCE_S4 = WARN + 0x01C REFERENCE_S5 = WARN + 0x01D REFERENCE_S6 = WARN + 0x01E NV_RATE = WARN + 0x020 LOCKOUT = WARN + 0x021 RETRY = WARN + 0x022 NV_UNAVAILABLE = WARN + 0x023 NOT_USED = WARN + 0x07F H = 0x000 P = 0x040 S = 0x800 RC1 = 0x100 RC2 = 0x200 RC3 = 0x300 RC4 = 0x400 RC5 = 0x500 RC6 = 0x600 RC7 = 0x700 RC8 = 0x800 RC9 = 0x900 A = 0xA00 B = 0xB00 C = 0xC00 D = 0xD00 E = 0xE00 F = 0xF00 N_MASK = 0xF00 class TSS2_RC(TPM_BASE_RC): RC_LAYER_SHIFT = 16 RC_LAYER_MASK = 0xFF << RC_LAYER_SHIFT TPM_RC_LAYER = 0 << RC_LAYER_SHIFT FEATURE_RC_LAYER = 6 << RC_LAYER_SHIFT ESAPI_RC_LAYER = 7 << RC_LAYER_SHIFT SYS_RC_LAYER = 8 << RC_LAYER_SHIFT MU_RC_LAYER = 9 << RC_LAYER_SHIFT TCTI_RC_LAYER = 10 << RC_LAYER_SHIFT RESMGR_RC_LAYER = 11 << RC_LAYER_SHIFT RESMGR_TPM_RC_LAYER = 12 << RC_LAYER_SHIFT POLICY_RC_LAYER = 13 << RC_LAYER_SHIFT BASE_RC_GENERAL_FAILURE = 1 BASE_RC_NOT_IMPLEMENTED = 2 BASE_RC_BAD_CONTEXT = 3 BASE_RC_ABI_MISMATCH = 4 BASE_RC_BAD_REFERENCE = 5 BASE_RC_INSUFFICIENT_BUFFER = 6 BASE_RC_BAD_SEQUENCE = 7 BASE_RC_NO_CONNECTION = 8 BASE_RC_TRY_AGAIN = 9 BASE_RC_IO_ERROR = 10 BASE_RC_BAD_VALUE = 11 BASE_RC_NOT_PERMITTED = 12 BASE_RC_INVALID_SESSIONS = 13 BASE_RC_NO_DECRYPT_PARAM = 14 BASE_RC_NO_ENCRYPT_PARAM = 15 BASE_RC_BAD_SIZE = 16 BASE_RC_MALFORMED_RESPONSE = 17 BASE_RC_INSUFFICIENT_CONTEXT = 18 BASE_RC_INSUFFICIENT_RESPONSE = 19 BASE_RC_INCOMPATIBLE_TCTI = 20 BASE_RC_NOT_SUPPORTED = 21 BASE_RC_BAD_TCTI_STRUCTURE = 22 BASE_RC_MEMORY = 23 BASE_RC_BAD_TR = 24 BASE_RC_MULTIPLE_DECRYPT_SESSIONS = 25 BASE_RC_MULTIPLE_ENCRYPT_SESSIONS = 26 BASE_RC_RSP_AUTH_FAILED = 27 BASE_RC_NO_CONFIG = 28 BASE_RC_BAD_PATH = 29 BASE_RC_NOT_DELETABLE = 30 BASE_RC_PATH_ALREADY_EXISTS = 31 BASE_RC_KEY_NOT_FOUND = 32 BASE_RC_SIGNATURE_VERIFICATION_FAILED = 33 BASE_RC_HASH_MISMATCH = 34 BASE_RC_KEY_NOT_DUPLICABLE = 35 BASE_RC_PATH_NOT_FOUND = 36 BASE_RC_NO_CERT = 37 BASE_RC_NO_PCR = 38 BASE_RC_PCR_NOT_RESETTABLE = 39 BASE_RC_BAD_TEMPLATE = 40 BASE_RC_AUTHORIZATION_FAILED = 41 BASE_RC_AUTHORIZATION_UNKNOWN = 42 BASE_RC_NV_NOT_READABLE = 43 BASE_RC_NV_TOO_SMALL = 44 BASE_RC_NV_NOT_WRITEABLE = 45 BASE_RC_POLICY_UNKNOWN = 46 BASE_RC_NV_WRONG_TYPE = 47 BASE_RC_NAME_ALREADY_EXISTS = 48 BASE_RC_NO_TPM = 49 BASE_RC_BAD_KEY = 50 BASE_RC_NO_HANDLE = 51 BASE_RC_NOT_PROVISIONED = 52 BASE_RC_ALREADY_PROVISIONED = 53 BASE_RC_CALLBACK_NULL = 54 LAYER_IMPLEMENTATION_SPECIFIC_OFFSET = 0xF800 LEVEL_IMPLEMENTATION_SPECIFIC_SHIFT = 11 RC_SUCCESS = 0 TCTI_RC_GENERAL_FAILURE = TCTI_RC_LAYER | BASE_RC_GENERAL_FAILURE TCTI_RC_NOT_IMPLEMENTED = TCTI_RC_LAYER | BASE_RC_NOT_IMPLEMENTED TCTI_RC_BAD_CONTEXT = TCTI_RC_LAYER | BASE_RC_BAD_CONTEXT TCTI_RC_ABI_MISMATCH = TCTI_RC_LAYER | BASE_RC_ABI_MISMATCH TCTI_RC_BAD_REFERENCE = TCTI_RC_LAYER | BASE_RC_BAD_REFERENCE TCTI_RC_INSUFFICIENT_BUFFER = TCTI_RC_LAYER | BASE_RC_INSUFFICIENT_BUFFER TCTI_RC_BAD_SEQUENCE = TCTI_RC_LAYER | BASE_RC_BAD_SEQUENCE TCTI_RC_NO_CONNECTION = TCTI_RC_LAYER | BASE_RC_NO_CONNECTION TCTI_RC_TRY_AGAIN = TCTI_RC_LAYER | BASE_RC_TRY_AGAIN TCTI_RC_IO_ERROR = TCTI_RC_LAYER | BASE_RC_IO_ERROR TCTI_RC_BAD_VALUE = TCTI_RC_LAYER | BASE_RC_BAD_VALUE TCTI_RC_NOT_PERMITTED = TCTI_RC_LAYER | BASE_RC_NOT_PERMITTED TCTI_RC_MALFORMED_RESPONSE = TCTI_RC_LAYER | BASE_RC_MALFORMED_RESPONSE TCTI_RC_NOT_SUPPORTED = TCTI_RC_LAYER | BASE_RC_NOT_SUPPORTED TCTI_RC_MEMORY = TCTI_RC_LAYER | BASE_RC_MEMORY SYS_RC_GENERAL_FAILURE = SYS_RC_LAYER | BASE_RC_GENERAL_FAILURE SYS_RC_ABI_MISMATCH = SYS_RC_LAYER | BASE_RC_ABI_MISMATCH SYS_RC_BAD_REFERENCE = SYS_RC_LAYER | BASE_RC_BAD_REFERENCE SYS_RC_INSUFFICIENT_BUFFER = SYS_RC_LAYER | BASE_RC_INSUFFICIENT_BUFFER SYS_RC_BAD_SEQUENCE = SYS_RC_LAYER | BASE_RC_BAD_SEQUENCE SYS_RC_BAD_VALUE = SYS_RC_LAYER | BASE_RC_BAD_VALUE SYS_RC_INVALID_SESSIONS = SYS_RC_LAYER | BASE_RC_INVALID_SESSIONS SYS_RC_NO_DECRYPT_PARAM = SYS_RC_LAYER | BASE_RC_NO_DECRYPT_PARAM SYS_RC_NO_ENCRYPT_PARAM = SYS_RC_LAYER | BASE_RC_NO_ENCRYPT_PARAM SYS_RC_BAD_SIZE = SYS_RC_LAYER | BASE_RC_BAD_SIZE SYS_RC_MALFORMED_RESPONSE = SYS_RC_LAYER | BASE_RC_MALFORMED_RESPONSE SYS_RC_INSUFFICIENT_CONTEXT = SYS_RC_LAYER | BASE_RC_INSUFFICIENT_CONTEXT SYS_RC_INSUFFICIENT_RESPONSE = SYS_RC_LAYER | BASE_RC_INSUFFICIENT_RESPONSE SYS_RC_INCOMPATIBLE_TCTI = SYS_RC_LAYER | BASE_RC_INCOMPATIBLE_TCTI SYS_RC_BAD_TCTI_STRUCTURE = SYS_RC_LAYER | BASE_RC_BAD_TCTI_STRUCTURE MU_RC_GENERAL_FAILURE = MU_RC_LAYER | BASE_RC_GENERAL_FAILURE MU_RC_BAD_REFERENCE = MU_RC_LAYER | BASE_RC_BAD_REFERENCE MU_RC_BAD_SIZE = MU_RC_LAYER | BASE_RC_BAD_SIZE MU_RC_BAD_VALUE = MU_RC_LAYER | BASE_RC_BAD_VALUE MU_RC_INSUFFICIENT_BUFFER = MU_RC_LAYER | BASE_RC_INSUFFICIENT_BUFFER ESYS_RC_GENERAL_FAILURE = ESAPI_RC_LAYER | BASE_RC_GENERAL_FAILURE ESYS_RC_NOT_IMPLEMENTED = ESAPI_RC_LAYER | BASE_RC_NOT_IMPLEMENTED ESYS_RC_ABI_MISMATCH = ESAPI_RC_LAYER | BASE_RC_ABI_MISMATCH ESYS_RC_BAD_REFERENCE = ESAPI_RC_LAYER | BASE_RC_BAD_REFERENCE ESYS_RC_INSUFFICIENT_BUFFER = ESAPI_RC_LAYER | BASE_RC_INSUFFICIENT_BUFFER ESYS_RC_BAD_SEQUENCE = ESAPI_RC_LAYER | BASE_RC_BAD_SEQUENCE ESYS_RC_INVALID_SESSIONS = ESAPI_RC_LAYER | BASE_RC_INVALID_SESSIONS ESYS_RC_TRY_AGAIN = ESAPI_RC_LAYER | BASE_RC_TRY_AGAIN ESYS_RC_IO_ERROR = ESAPI_RC_LAYER | BASE_RC_IO_ERROR ESYS_RC_BAD_VALUE = ESAPI_RC_LAYER | BASE_RC_BAD_VALUE ESYS_RC_NO_DECRYPT_PARAM = ESAPI_RC_LAYER | BASE_RC_NO_DECRYPT_PARAM ESYS_RC_NO_ENCRYPT_PARAM = ESAPI_RC_LAYER | BASE_RC_NO_ENCRYPT_PARAM ESYS_RC_BAD_SIZE = ESAPI_RC_LAYER | BASE_RC_BAD_SIZE ESYS_RC_MALFORMED_RESPONSE = ESAPI_RC_LAYER | BASE_RC_MALFORMED_RESPONSE ESYS_RC_INSUFFICIENT_CONTEXT = ESAPI_RC_LAYER | BASE_RC_INSUFFICIENT_CONTEXT ESYS_RC_INSUFFICIENT_RESPONSE = ESAPI_RC_LAYER | BASE_RC_INSUFFICIENT_RESPONSE ESYS_RC_INCOMPATIBLE_TCTI = ESAPI_RC_LAYER | BASE_RC_INCOMPATIBLE_TCTI ESYS_RC_BAD_TCTI_STRUCTURE = ESAPI_RC_LAYER | BASE_RC_BAD_TCTI_STRUCTURE ESYS_RC_MEMORY = ESAPI_RC_LAYER | BASE_RC_MEMORY ESYS_RC_BAD_TR = ESAPI_RC_LAYER | BASE_RC_BAD_TR ESYS_RC_MULTIPLE_DECRYPT_SESSIONS = ( ESAPI_RC_LAYER | BASE_RC_MULTIPLE_DECRYPT_SESSIONS ) ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS = ( ESAPI_RC_LAYER | BASE_RC_MULTIPLE_ENCRYPT_SESSIONS ) ESYS_RC_RSP_AUTH_FAILED = ESAPI_RC_LAYER | BASE_RC_RSP_AUTH_FAILED FAPI_RC_GENERAL_FAILURE = FEATURE_RC_LAYER | BASE_RC_GENERAL_FAILURE FAPI_RC_NOT_IMPLEMENTED = FEATURE_RC_LAYER | BASE_RC_NOT_IMPLEMENTED FAPI_RC_BAD_REFERENCE = FEATURE_RC_LAYER | BASE_RC_BAD_REFERENCE FAPI_RC_BAD_SEQUENCE = FEATURE_RC_LAYER | BASE_RC_BAD_SEQUENCE FAPI_RC_IO_ERROR = FEATURE_RC_LAYER | BASE_RC_IO_ERROR FAPI_RC_BAD_VALUE = FEATURE_RC_LAYER | BASE_RC_BAD_VALUE FAPI_RC_NO_DECRYPT_PARAM = FEATURE_RC_LAYER | BASE_RC_NO_DECRYPT_PARAM FAPI_RC_NO_ENCRYPT_PARAM = FEATURE_RC_LAYER | BASE_RC_NO_ENCRYPT_PARAM FAPI_RC_MEMORY = FEATURE_RC_LAYER | BASE_RC_MEMORY FAPI_RC_BAD_CONTEXT = FEATURE_RC_LAYER | BASE_RC_BAD_CONTEXT FAPI_RC_NO_CONFIG = FEATURE_RC_LAYER | BASE_RC_NO_CONFIG FAPI_RC_BAD_PATH = FEATURE_RC_LAYER | BASE_RC_BAD_PATH FAPI_RC_NOT_DELETABLE = FEATURE_RC_LAYER | BASE_RC_NOT_DELETABLE FAPI_RC_PATH_ALREADY_EXISTS = FEATURE_RC_LAYER | BASE_RC_PATH_ALREADY_EXISTS FAPI_RC_KEY_NOT_FOUND = FEATURE_RC_LAYER | BASE_RC_KEY_NOT_FOUND FAPI_RC_SIGNATURE_VERIFICATION_FAILED = ( FEATURE_RC_LAYER | BASE_RC_SIGNATURE_VERIFICATION_FAILED ) FAPI_RC_HASH_MISMATCH = FEATURE_RC_LAYER | BASE_RC_HASH_MISMATCH FAPI_RC_KEY_NOT_DUPLICABLE = FEATURE_RC_LAYER | BASE_RC_KEY_NOT_DUPLICABLE FAPI_RC_PATH_NOT_FOUND = FEATURE_RC_LAYER | BASE_RC_PATH_NOT_FOUND FAPI_RC_NO_CERT = FEATURE_RC_LAYER | BASE_RC_NO_CERT FAPI_RC_NO_PCR = FEATURE_RC_LAYER | BASE_RC_NO_PCR FAPI_RC_PCR_NOT_RESETTABLE = FEATURE_RC_LAYER | BASE_RC_PCR_NOT_RESETTABLE FAPI_RC_BAD_TEMPLATE = FEATURE_RC_LAYER | BASE_RC_BAD_TEMPLATE FAPI_RC_AUTHORIZATION_FAILED = FEATURE_RC_LAYER | BASE_RC_AUTHORIZATION_FAILED FAPI_RC_AUTHORIZATION_UNKNOWN = FEATURE_RC_LAYER | BASE_RC_AUTHORIZATION_UNKNOWN FAPI_RC_NV_NOT_READABLE = FEATURE_RC_LAYER | BASE_RC_NV_NOT_READABLE FAPI_RC_NV_TOO_SMALL = FEATURE_RC_LAYER | BASE_RC_NV_TOO_SMALL FAPI_RC_NV_NOT_WRITEABLE = FEATURE_RC_LAYER | BASE_RC_NV_NOT_WRITEABLE FAPI_RC_POLICY_UNKNOWN = FEATURE_RC_LAYER | BASE_RC_POLICY_UNKNOWN FAPI_RC_NV_WRONG_TYPE = FEATURE_RC_LAYER | BASE_RC_NV_WRONG_TYPE FAPI_RC_NAME_ALREADY_EXISTS = FEATURE_RC_LAYER | BASE_RC_NAME_ALREADY_EXISTS FAPI_RC_NO_TPM = FEATURE_RC_LAYER | BASE_RC_NO_TPM FAPI_RC_TRY_AGAIN = FEATURE_RC_LAYER | BASE_RC_TRY_AGAIN FAPI_RC_BAD_KEY = FEATURE_RC_LAYER | BASE_RC_BAD_KEY FAPI_RC_NO_HANDLE = FEATURE_RC_LAYER | BASE_RC_NO_HANDLE FAPI_RC_NOT_PROVISIONED = FEATURE_RC_LAYER | BASE_RC_NOT_PROVISIONED FAPI_RC_ALREADY_PROVISIONED = FEATURE_RC_LAYER | BASE_RC_ALREADY_PROVISIONED POLICY_RC_GENERAL_FAILURE = POLICY_RC_LAYER | BASE_RC_GENERAL_FAILURE POLICY_RC_IO_ERROR = POLICY_RC_LAYER | BASE_RC_IO_ERROR POLICY_RC_AUTHORIZATION_UNKNOWN = POLICY_RC_LAYER | BASE_RC_AUTHORIZATION_UNKNOWN POLICY_RC_BAD_VALUE = POLICY_RC_LAYER | BASE_RC_BAD_VALUE POLICY_RC_MEMORY = POLICY_RC_LAYER | BASE_RC_MEMORY POLICY_RC_BAD_REFERENCE = POLICY_RC_LAYER | BASE_RC_BAD_REFERENCE POLICY_RC_BAD_TEMPLATE = POLICY_RC_LAYER | BASE_RC_BAD_TEMPLATE POLICY_RC_POLICY_NOT_CALCULATED = POLICY_RC_LAYER | BASE_RC_NOT_PROVISIONED POLICY_RC_BUFFER_TOO_SMALL = POLICY_RC_LAYER | BASE_RC_BAD_SIZE POLICY_RC_NULL_CALLBACK = POLICY_RC_LAYER | BASE_RC_CALLBACK_NULL class TPM2_EO(TPM_FRIENDLY_INT): EQ = 0x0000 NEQ = 0x0001 SIGNED_GT = 0x0002 UNSIGNED_GT = 0x0003 SIGNED_LT = 0x0004 UNSIGNED_LT = 0x0005 SIGNED_GE = 0x0006 UNSIGNED_GE = 0x0007 SIGNED_LE = 0x0008 UNSIGNED_LE = 0x0009 BITSET = 0x000A BITCLEAR = 0x000B class TPM2_ST(TPM_FRIENDLY_INT): RSP_COMMAND = 0x00C4 NULL = 0x8000 NO_SESSIONS = 0x8001 SESSIONS = 0x8002 ATTEST_NV = 0x8014 ATTEST_COMMAND_AUDIT = 0x8015 ATTEST_SESSION_AUDIT = 0x8016 ATTEST_CERTIFY = 0x8017 ATTEST_QUOTE = 0x8018 ATTEST_TIME = 0x8019 ATTEST_CREATION = 0x801A CREATION = 0x8021 VERIFIED = 0x8022 AUTH_SECRET = 0x8023 HASHCHECK = 0x8024 AUTH_SIGNED = 0x8025 FU_MANIFEST = 0x8029 class TPM2_SU(TPM_FRIENDLY_INT): CLEAR = 0x0000 STATE = 0x0001 class TPM2_SE(TPM_FRIENDLY_INT): HMAC = 0x00 POLICY = 0x01 TRIAL = 0x03 class TPM2_CAP(TPM_FRIENDLY_INT): FIRST = 0x00000000 ALGS = 0x00000000 HANDLES = 0x00000001 COMMANDS = 0x00000002 PP_COMMANDS = 0x00000003 AUDIT_COMMANDS = 0x00000004 PCRS = 0x00000005 TPM_PROPERTIES = 0x00000006 PCR_PROPERTIES = 0x00000007 ECC_CURVES = 0x00000008 AUTH_POLICIES = 0x00000009 ACT = 0x0000000A LAST = 0x0000000A VENDOR_PROPERTY = 0x00000100 class TPMI_YES_NO(TPM_FRIENDLY_INT): YES = 1 NO = 0 class TPM_AT(TPM_FRIENDLY_INT): ANY = 0x00000000 ERROR = 0x00000001 PV1 = 0x00000002 VEND = 0x80000000 class TPM2_PT(TPM_FRIENDLY_INT): NONE = 0x00000000 GROUP = 0x00000100 FIXED = GROUP * 1 VAR = GROUP * 2 LOCKOUT_COUNTER = VAR + 14 LEVEL = FIXED + 1 REVISION = FIXED + 2 DAY_OF_YEAR = FIXED + 3 YEAR = FIXED + 4 MANUFACTURER = FIXED + 5 FAMILY_INDICATOR = FIXED + 0 INPUT_BUFFER = FIXED + 13 ACTIVE_SESSIONS_MAX = FIXED + 17 CONTEXT_GAP_MAX = FIXED + 20 MEMORY = FIXED + 24 CLOCK_UPDATE = FIXED + 25 ORDERLY_COUNT = FIXED + 29 MAX_COMMAND_SIZE = FIXED + 30 MAX_RESPONSE_SIZE = FIXED + 31 MAX_DIGEST = FIXED + 32 MAX_OBJECT_CONTEXT = FIXED + 33 MAX_SESSION_CONTEXT = FIXED + 34 SPLIT_MAX = FIXED + 40 TOTAL_COMMANDS = FIXED + 41 VENDOR_COMMANDS = FIXED + 43 MODES = FIXED + 45 PERMANENT = VAR + 0 STARTUP_CLEAR = VAR + 1 LIBRARY_COMMANDS = FIXED + 42 ALGORITHM_SET = VAR + 12 LOADED_CURVES = VAR + 13 MAX_AUTH_FAIL = VAR + 15 LOCKOUT_INTERVAL = VAR + 16 LOCKOUT_RECOVERY = VAR + 17 class TPM2_PT_VENDOR(TPM_FRIENDLY_INT): STRING_1 = TPM2_PT.FIXED + 6 STRING_2 = TPM2_PT.FIXED + 7 STRING_3 = TPM2_PT.FIXED + 8 STRING_4 = TPM2_PT.FIXED + 9 TPM_TYPE = TPM2_PT.FIXED + 10 class TPM2_PT_FIRMWARE(TPM_FRIENDLY_INT): VERSION_1 = TPM2_PT.FIXED + 11 VERSION_2 = TPM2_PT.FIXED + 12 class TPM2_PT_HR(TPM_FRIENDLY_INT): LOADED_MIN = TPM2_PT.FIXED + 16 NV_INDEX = TPM2_PT.VAR + 2 LOADED = TPM2_PT.VAR + 3 LOADED_AVAIL = TPM2_PT.VAR + 4 ACTIVE = TPM2_PT.VAR + 5 ACTIVE_AVAIL = TPM2_PT.VAR + 6 TRANSIENT_AVAIL = TPM2_PT.VAR + 7 PERSISTENT = TPM2_PT.VAR + 8 PERSISTENT_AVAIL = TPM2_PT.VAR + 9 TRANSIENT_MIN = TPM2_PT.FIXED + 14 PERSISTENT_MIN = TPM2_PT.FIXED + 15 class TPM2_PT_NV(TPM_FRIENDLY_INT): COUNTERS_MAX = TPM2_PT.FIXED + 22 INDEX_MAX = TPM2_PT.FIXED + 23 BUFFER_MAX = TPM2_PT.FIXED + 44 COUNTERS = TPM2_PT.VAR + 10 COUNTERS_AVAIL = TPM2_PT.VAR + 11 WRITE_RECOVERY = TPM2_PT.VAR + 18 class TPM2_PT_CONTEXT(TPM_FRIENDLY_INT): HASH = TPM2_PT.FIXED + 26 SYM = TPM2_PT.FIXED + 27 SYM_SIZE = TPM2_PT.FIXED + 28 class TPM2_PT_PS(TPM_FRIENDLY_INT): FAMILY_INDICATOR = TPM2_PT.FIXED + 35 LEVEL = TPM2_PT.FIXED + 36 REVISION = TPM2_PT.FIXED + 37 DAY_OF_YEAR = TPM2_PT.FIXED + 38 YEAR = TPM2_PT.FIXED + 39 class TPM2_PT_AUDIT(TPM_FRIENDLY_INT): COUNTER_0 = TPM2_PT.VAR + 19 COUNTER_1 = TPM2_PT.VAR + 20 class TPM2_PT_PCR(TPM_FRIENDLY_INT): FIRST = 0x00000000 SAVE = 0x00000000 EXTEND_L0 = 0x00000001 RESET_L0 = 0x00000002 EXTEND_L1 = 0x00000003 RESET_L1 = 0x00000004 EXTEND_L2 = 0x00000005 RESET_L2 = 0x00000006 EXTEND_L3 = 0x00000007 RESET_L3 = 0x00000008 EXTEND_L4 = 0x00000009 RESET_L4 = 0x0000000A NO_INCREMENT = 0x00000011 DRTM_RESET = 0x00000012 POLICY = 0x00000013 AUTH = 0x00000014 LAST = 0x00000014 COUNT = TPM2_PT.FIXED + 18 SELECT_MIN = TPM2_PT.FIXED + 19 class TPM2_PS(TPM_FRIENDLY_INT): MAIN = 0x00000000 PC = 0x00000001 PDA = 0x00000002 CELL_PHONE = 0x00000003 SERVER = 0x00000004 PERIPHERAL = 0x00000005 TSS = 0x00000006 STORAGE = 0x00000007 AUTHENTICATION = 0x00000008 EMBEDDED = 0x00000009 HARDCOPY = 0x0000000A INFRASTRUCTURE = 0x0000000B VIRTUALIZATION = 0x0000000C TNC = 0x0000000D MULTI_TENANT = 0x0000000E TC = 0x0000000F class TPM2_HT(TPM_FRIENDLY_INT): PCR = 0x00 NV_INDEX = 0x01 HMAC_SESSION = 0x02 LOADED_SESSION = 0x02 POLICY_SESSION = 0x03 SAVED_SESSION = 0x03 PERMANENT = 0x40 TRANSIENT = 0x80 PERSISTENT = 0x81 class TPMA_SESSION(TPMA_FRIENDLY_INTLIST): CONTINUESESSION = 0x00000001 AUDITEXCLUSIVE = 0x00000002 AUDITRESET = 0x00000004 DECRYPT = 0x00000020 ENCRYPT = 0x00000040 AUDIT = 0x00000080 class TPMA_LOCALITY(TPMA_FRIENDLY_INTLIST): ZERO = 0x00000001 ONE = 0x00000002 TWO = 0x00000004 THREE = 0x00000008 FOUR = 0x00000010 EXTENDED_MASK = 0x000000E0 EXTENDED_SHIFT = 5 @classmethod def create_extended(cls, value): x = (1 << cls.EXTENDED_SHIFT) + value if x > 255: raise ValueError("Extended Localities must be less than 256") return x @classmethod def parse(cls, value: str) -> "TPMA_LOCALITY": """Converts a string of | separated localities or an extended locality into a TPMA_LOCALITY instance Args: value (str): The string "bitwise" expression of the localities or the extended locality. Returns: The locality or set of localities as a TPMA_LOCALITY instance. Raises: TypeError: If the value is not a str. ValueError: If a field portion of the str does not match a constant. Examples: TPMA_LOCALITY.parse("zero|one") -> 0x03 TPMA_LOCALITY.parse("0xf0") -> 0xf0 """ try: return cls(value, base=0) except ValueError: pass return super().parse(value) def __str__(self) -> str: """Given a set of localities or an extended locality, return the string representation Returns: (str): a bitwise string value of the localities or the exteded locality. Example: str(TPMA_LOCALITY.THREE|TPMA_LOCALITY.FOUR) -> 'three|four' str(TPMA_LOCALITY(0xf0)) -> '0xf0' """ if self > 31: return f"{self:#x}" return super().__str__() class TPM2_NT(TPM_FRIENDLY_INT): ORDINARY = 0x0 COUNTER = 0x1 BITS = 0x2 EXTEND = 0x4 PIN_FAIL = 0x8 PIN_PASS = 0x9 class TPM2_HR(TPM_FRIENDLY_INT): HANDLE_MASK = 0x00FFFFFF RANGE_MASK = 0xFF000000 SHIFT = 24 PCR = TPM2_HT.PCR << SHIFT HMAC_SESSION = TPM2_HT.HMAC_SESSION << SHIFT POLICY_SESSION = TPM2_HT.POLICY_SESSION << SHIFT TRANSIENT = TPM2_HT.TRANSIENT << SHIFT PERSISTENT = TPM2_HT.PERSISTENT << SHIFT NV_INDEX = TPM2_HT.NV_INDEX << SHIFT PERMANENT = TPM2_HT.PERMANENT << SHIFT class TPM2_HC(TPM_FRIENDLY_INT): HR_HANDLE_MASK = 0x00FFFFFF HR_RANGE_MASK = 0xFF000000 HR_SHIFT = 24 HR_PCR = TPM2_HT.PCR << HR_SHIFT HR_HMAC_SESSION = TPM2_HT.HMAC_SESSION << HR_SHIFT HR_POLICY_SESSION = TPM2_HT.POLICY_SESSION << HR_SHIFT HR_TRANSIENT = TPM2_HT.TRANSIENT << HR_SHIFT HR_PERSISTENT = TPM2_HT.PERSISTENT << HR_SHIFT HR_NV_INDEX = TPM2_HT.NV_INDEX << HR_SHIFT HR_PERMANENT = TPM2_HT.PERMANENT << HR_SHIFT PCR_FIRST = HR_PCR + 0 PCR_LAST = HR_PCR + TPM2_MAX.PCRS HMAC_SESSION_FIRST = HR_HMAC_SESSION + 0 HMAC_SESSION_LAST = HMAC_SESSION_FIRST + 0x00FFFFFE LOADED_SESSION_FIRST = HMAC_SESSION_FIRST LOADED_SESSION_LAST = HMAC_SESSION_LAST POLICY_SESSION_FIRST = HR_POLICY_SESSION + 0 POLICY_SESSION_LAST = POLICY_SESSION_FIRST + 0x00FFFFFE TRANSIENT_FIRST = HR_TRANSIENT + 0 ACTIVE_SESSION_FIRST = POLICY_SESSION_FIRST ACTIVE_SESSION_LAST = POLICY_SESSION_LAST TRANSIENT_LAST = TRANSIENT_FIRST + 0x00FFFFFE PERSISTENT_FIRST = HR_PERSISTENT + 0 PERSISTENT_LAST = PERSISTENT_FIRST + 0x00FFFFFF PLATFORM_PERSISTENT = PERSISTENT_FIRST + 0x00800000 NV_INDEX_FIRST = HR_NV_INDEX + 0 NV_INDEX_LAST = HR_NV_INDEX + 0x00FFFFFF PERMANENT_FIRST = TPM2_RH.FIRST PERMANENT_LAST = TPM2_RH.LAST HR_NV_AC = (TPM2_HT.NV_INDEX << HR_SHIFT) + 0xD00000 NV_AC_FIRST = HR_NV_AC + 0 NV_AC_LAST = HR_NV_AC + 0x0000FFFF class TPM2_CLOCK(TPM_FRIENDLY_INT): COARSE_SLOWER = -3 MEDIUM_SLOWER = -2 FINE_SLOWER = -1 NO_CHANGE = 0 FINE_FASTER = 1 MEDIUM_FASTER = 2 COARSE_FASTER = 3 class TPM2_CLOCK_ADJUST(TPM2_CLOCK): pass class TPMA_NV(TPMA_FRIENDLY_INTLIST): _FIXUP_MAP = {"NODA": "NO_DA"} PPWRITE = 0x00000001 OWNERWRITE = 0x00000002 AUTHWRITE = 0x00000004 POLICYWRITE = 0x00000008 TPM2_NT_MASK = 0x000000F0 TPM2_NT_SHIFT = 4 POLICY_DELETE = 0x00000400 WRITELOCKED = 0x00000800 WRITEALL = 0x00001000 WRITEDEFINE = 0x00002000 WRITE_STCLEAR = 0x00004000 GLOBALLOCK = 0x00008000 PPREAD = 0x00010000 OWNERREAD = 0x00020000 AUTHREAD = 0x00040000 POLICYREAD = 0x00080000 NO_DA = 0x02000000 ORDERLY = 0x04000000 CLEAR_STCLEAR = 0x08000000 READLOCKED = 0x10000000 WRITTEN = 0x20000000 PLATFORMCREATE = 0x40000000 READ_STCLEAR = 0x80000000 _MASKS = ((TPM2_NT_MASK, TPM2_NT_SHIFT, "nt"),) @property def nt(self) -> TPM2_NT: """TPM2_NT: The type of the NV area""" return TPM2_NT((self & self.TPM2_NT_MASK) >> self.TPM2_NT_SHIFT) class TPMA_CC(TPMA_FRIENDLY_INTLIST): COMMANDINDEX_MASK = 0x0000FFFF COMMANDINDEX_SHIFT = 0 RESERVED1_MASK = 0x003F0000 NV = 0x00400000 EXTENSIVE = 0x00800000 FLUSHED = 0x01000000 CHANDLES_MASK = 0x0E000000 CHANDLES_SHIFT = 25 RHANDLE = 0x10000000 V = 0x20000000 RES_MASK = 0xC0000000 RES_SHIFT = 30 _MASKS = ( (COMMANDINDEX_MASK, COMMANDINDEX_SHIFT, "commandindex"), (CHANDLES_MASK, CHANDLES_SHIFT, "chandles"), ) @property def commandindex(self) -> int: """int: The command index""" return self & self.COMMANDINDEX_MASK @property def chandles(self) -> int: """int: The number of handles in the handle area""" return (self & self.CHANDLES_MASK) >> self.CHANDLES_SHIFT class TPMA_OBJECT(TPMA_FRIENDLY_INTLIST): FIXEDTPM = 0x00000002 STCLEAR = 0x00000004 FIXEDPARENT = 0x00000010 SENSITIVEDATAORIGIN = 0x00000020 USERWITHAUTH = 0x00000040 ADMINWITHPOLICY = 0x00000080 FIRMWARELIMITED = 0x00000100 SVNLIMITED = 0x00000200 NODA = 0x00000400 ENCRYPTEDDUPLICATION = 0x00000800 RESTRICTED = 0x00010000 DECRYPT = 0x00020000 SIGN_ENCRYPT = 0x00040000 X509SIGN = 0x00080000 DEFAULT_TPM2_TOOLS_CREATE_ATTRS = ( DECRYPT | SIGN_ENCRYPT | FIXEDTPM | FIXEDPARENT | SENSITIVEDATAORIGIN | USERWITHAUTH ) DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS = ( RESTRICTED | DECRYPT | FIXEDTPM | FIXEDPARENT | SENSITIVEDATAORIGIN | USERWITHAUTH ) _FIXUP_MAP = { "SIGN": "SIGN_ENCRYPT", "ENCRYPT": "SIGN_ENCRYPT", } class TPMA_ALGORITHM(TPM_FRIENDLY_INT): ASYMMETRIC = 0x00000001 SYMMETRIC = 0x00000002 HASH = 0x00000004 OBJECT = 0x00000008 RESERVED1_MASK = 0x000000F0 SIGNING = 0x00000100 ENCRYPTING = 0x00000200 METHOD = 0x00000400 class TPMA_PERMANENT(TPMA_FRIENDLY_INTLIST): OWNERAUTHSET = 0x00000001 ENDORSEMENTAUTHSET = 0x00000002 LOCKOUTAUTHSET = 0x00000004 RESERVED1_MASK = 0x000000F8 DISABLECLEAR = 0x00000100 INLOCKOUT = 0x00000200 TPMGENERATEDEPS = 0x00000400 RESERVED2_MASK = 0xFFFFF800 class TPMA_STARTUP(TPMA_FRIENDLY_INTLIST): CLEAR_PHENABLE = 0x00000001 CLEAR_SHENABLE = 0x00000002 CLEAR_EHENABLE = 0x00000004 CLEAR_PHENABLENV = 0x00000008 CLEAR_RESERVED1_MASK = 0x7FFFFFF0 CLEAR_ORDERLY = 0x80000000 class TPMA_MEMORY(TPM_FRIENDLY_INT): SHAREDRAM = 0x00000001 SHAREDNV = 0x00000002 OBJECTCOPIEDTORAM = 0x00000004 class TPMA_MODES(TPMA_FRIENDLY_INTLIST): FIPS_140_2 = 0x00000001 RESERVED1_MASK = 0xFFFFFFFE class TPMA_X509_KEY_USAGE(TPMA_FRIENDLY_INTLIST): DECIPHER_ONLY = 0x00800000 ENCIPHER_ONLY = 0x01000000 CRLSIGN = 0x02000000 KEYCERTSIGN = 0x04000000 KEYAGREEMENT = 0x08000000 DATAENCIPHERMENT = 0x10000000 KEYENCIPHERMENT = 0x20000000 NONREPUDIATION = 0x40000000 DIGITALSIGNATURE = 0x80000000 class TPMA_ACT(TPMA_FRIENDLY_INTLIST): SIGNALED = 0x00000000 PRESERVESIGNALED = 0x00000001 # # We specifically keep these constants around even when FAPI is missing so they may be used # without conditional worry and we DONT use lib prefix here because the constants are only # present if FAPI is installed. So just use the values directly. # class FAPI_ESYSBLOB(TPM_FRIENDLY_INT): CONTEXTLOAD = 1 DESERIALIZE = 2 class TSS2_POLICY_PCR_SELECTOR(TPM_FRIENDLY_INT): PCR_SELECT = 0 PCR_SELECTION = 1 # Max value for INT32 TPM2_MAX_EXPIRATION = -0x7FFFFFFF tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/cryptography.py000066400000000000000000000415021506405471500222670ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .ESAPI import ESAPI from .constants import ESYS_TR, TPM2_ALG, TPMA_OBJECT, TPM2_ST, TPM2_RH from .types import ( TPMT_RSA_DECRYPT, TPM2B_DATA, TPMT_SIG_SCHEME, TPMT_TK_HASHCHECK, TPM2B_ECC_POINT, TPMT_ASYM_SCHEME, TPMT_ECC_SCHEME, TPMU_SIG_SCHEME, ) from .internal.crypto import ( public_to_key, _get_curve, _rsa_decrypt_padding_to_scheme, _rsa_sign_padding_to_scheme, _int_to_buffer, _ecc_sign_algorithm_to_scheme, _get_digest, ) from typing import Union from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric.utils import Prehashed from cryptography.hazmat.primitives.serialization import ( Encoding, PrivateFormat, KeySerializationEncryption, ) def _compare_schemes( in_scheme: Union[TPMT_RSA_DECRYPT, TPMT_SIG_SCHEME], key_scheme: TPMT_SIG_SCHEME ) -> None: """Compare a keys scheme and any scheme passed to sign/decrypt functions. Raises: ValueError: On any scheme mismatch. """ if key_scheme.scheme == TPM2_ALG.NULL: return if in_scheme.scheme != key_scheme.scheme: raise ValueError( f"invalid scheme, scheme has {in_scheme.scheme} but key requires {key_scheme.scheme}" ) if in_scheme.scheme == TPM2_ALG.RSAES: return if isinstance(in_scheme.details, TPMU_SIG_SCHEME): halg = in_scheme.details.any.hashAlg else: halg = in_scheme.details.anySig.hashAlg if halg != key_scheme.details.anySig.hashAlg: raise ValueError( f"digest algorithm mismatch, scheme has {halg} but key requires {key_scheme.details.anySig.hashAlg}" ) class tpm_rsa_private_key(rsa.RSAPrivateKey): """Interface to a TPM RSA key for use with the cryptography module. Args: ectx (ESAPI): The ESAPI instance to use. handle (ESYS_TR): The key handle. session (ESYS_TR): The session to authorize usage of the key, default is ESYS_TR.PASSWORD Notes: It is recommended to use the :func:`get_digest_algorithm`, :func:`get_decryption_padding` and :func:`get_signature_padding` methods for highest compatibility. Raises: ValueError: If the key has the restricted bit set or if the handle doesn't reference an RSA key. """ def __init__( self, ectx: ESAPI, handle: ESYS_TR, session: ESYS_TR = ESYS_TR.PASSWORD ): self._handle = handle self._session = session self._ectx = ectx public, _, _ = ectx.read_public(handle) self._public = public.publicArea if self._public.type != TPM2_ALG.RSA: raise ValueError( f"invalid key type, expected {TPM2_ALG.RSA}, got {self._public.type}" ) if self._public.objectAttributes & TPMA_OBJECT.RESTRICTED: raise ValueError( "TPM key does not allow generic signing and/or decryption (object attribute restricted is set)" ) def decrypt(self, ciphertext: bytes, padding: padding) -> bytes: """Implements the decrypt interface. See :py:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.decrypt` for documentation. Notes: If a non-empty label is used with OAEP padding, this will fail. Raises: ValueError: if the requested padding isn't supported by the key. """ if not self._public.objectAttributes & TPMA_OBJECT.DECRYPT: raise ValueError( "TPM key does not allow decryption (object attribute decrypt is not set)" ) scheme = TPMT_RSA_DECRYPT() _rsa_decrypt_padding_to_scheme(padding, scheme) _compare_schemes(scheme, self._public.parameters.rsaDetail.scheme) data2b = self._ectx.rsa_decrypt( self._handle, ciphertext, scheme, TPM2B_DATA(), session1=self._session ) return bytes(data2b) def public_key(self) -> rsa.RSAPublicKey: """Get the public key. Returns: the public part of the RSA key as a :py:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`. """ return public_to_key(self._public) @property def key_size(self) -> int: """The RSA key size""" return self._public.parameters.rsaDetail.keyBits def get_digest_algorithm(self) -> hashes.HashAlgorithm: """Get an usable digest algorithm for use with the key. If any scheme with a specified digest algorithm is specified return that algorithm. Otherwise the name digest algorithm is returned. The returned digest algorithm can be used with different cryptography functions. Returns: The digest algorithm as a :py:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` subclass. Raises: ValueError: If the digest algorithm is not supported. """ if self._public.parameters.rsaDetail.scheme.scheme in ( TPM2_ALG.RSASSA, TPM2_ALG.RSAPSS, TPM2_ALG.OAEP, ): tpm_alg = self._public.parameters.rsaDetail.scheme.details.anySig.hashAlg else: tpm_alg = self._public.nameAlg halg = _get_digest(tpm_alg) if halg is None: raise ValueError(f"unsupported digest algorithm {tpm_alg}") return halg def get_decryption_padding(self) -> padding.AsymmetricPadding: """Get a padding configuration for use with the decrypt method. If the key has a scheme specified, use that scheme. Otherwise, use OAEP as the default. Returns: An instance of :py:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. Raises: ValueError: If the either the scheme or digest algorithm is unsupported. """ if self._public.parameters.asymDetail.scheme.scheme == TPM2_ALG.NULL: scheme = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.OAEP) scheme.details.anySig.hashAlg = self._public.nameAlg else: scheme = self._public.parameters.asymDetail.scheme if scheme.scheme == TPM2_ALG.OAEP: algorithm = self.get_digest_algorithm() decrypt_padding = padding.OAEP( mgf=padding.MGF1(algorithm=algorithm()), algorithm=algorithm(), label=b"", ) elif scheme.scheme == TPM2_ALG.RSAES: decrypt_padding = padding.PKCS1v15() else: raise ValueError(f"unsupported decryption scheme {scheme.scheme}") return decrypt_padding def get_signature_padding(self) -> padding.AsymmetricPadding: """Get a padding configuration for use with the sign method. If the key has a scheme specified, use that scheme. Otherwise, use PSS as the default. Returns: An instance of :py:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. Raises: ValueError if the either the scheme or digest algorithm is unsupported. """ if self._public.parameters.asymDetail.scheme.scheme == TPM2_ALG.NULL: scheme = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.RSAPSS) scheme.details.anySig.hashAlg = self._public.nameAlg else: scheme = self._public.parameters.asymDetail.scheme if scheme.scheme == TPM2_ALG.RSAPSS: algorithm = self.get_digest_algorithm() sign_padding = padding.PSS( mgf=padding.MGF1(algorithm=algorithm()), salt_length=padding.PSS.DIGEST_LENGTH, ) elif scheme.scheme == TPM2_ALG.RSASSA: sign_padding = padding.PKCS1v15() else: raise ValueError(f"unsupported signature scheme {scheme.scheme}") return sign_padding def sign( self, data: bytes, padding: padding, algorithm: Union[hashes.HashAlgorithm, Prehashed], ) -> bytes: """Implements the sign interface. See :py:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.sign` for documentationen. Notes: For PSS padding, the salt length should be set to the length of the digest as that is the only setup the TPM uses. Raises: ValueError: If the requested padding isn't supported by the key or the sign_encrypt bit isn't set. """ if not self._public.objectAttributes & TPMA_OBJECT.SIGN_ENCRYPT: raise ValueError( "TPM key does not allow signing (object attribute sign_encrypt is not set)" ) if isinstance(algorithm, Prehashed): raise ValueError("Prehashed data is not supported") scheme = TPMT_SIG_SCHEME() _rsa_sign_padding_to_scheme(padding, type(algorithm), scheme) _compare_schemes(scheme, self._public.parameters.rsaDetail.scheme) h = hashes.Hash(algorithm) h.update(data) digest = h.finalize() validation = TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL) tpm_sig = self._ectx.sign( self._handle, digest, scheme, validation, session1=self._session ) return bytes(tpm_sig) def private_numbers(self) -> None: """Always raises a NotImplementedError.""" raise NotImplementedError() def private_bytes( self, encoding: Encoding, format: PrivateFormat, encryption_algorithm: KeySerializationEncryption, ) -> None: """Always raises a NotImplementedError.""" raise NotImplementedError() def __copy__(self) -> "tpm_rsa_private_key": """Returns a shallow copy of the private key.""" return tpm_rsa_private_key( ectx=self._ectx, handle=self._handle, session=self._session ) class tpm_ecc_private_key(ec.EllipticCurvePrivateKey): """Interface to a TPM ECC key for use with the cryptography module. Args: ectx (ESAPI): The ESAPI instance to use. handle (ESYS_TR): The key handle. session (ESYS_TR): The session to authorize usage of the key, default is ESYS_TR.PASSWORD Notes: It is recommended to use the :func:`get_digest_algorithm` and :func:`get_signature_algorithm` methods for highest compatibility. Raises: ValueError: If the key has the restricted bit set, the curve isn't supported or if the handle doesn't reference an ECC key. """ def __init__( self, ectx: ESAPI, handle: ESYS_TR, session: ESYS_TR = ESYS_TR.PASSWORD ): self._handle = handle self._session = session self._ectx = ectx public, _, _ = ectx.read_public(handle) self._public = public.publicArea if self._public.type != TPM2_ALG.ECC: raise ValueError( f"invalid key type, expected {TPM2_ALG.ECC}, got {self._public.type}" ) if self._public.objectAttributes & TPMA_OBJECT.RESTRICTED: raise ValueError( "TPM key does not allow generic signing and/or decryption (object attribute restricted is set)" ) cid = _get_curve(self._public.parameters.eccDetail.curveID) if cid is None: raise ValueError( f"unsupported curve {self._public.parameters.eccDetail.curveID}" ) self._curve = cid def exchange( self, algorithm: ec.ECDH, peer_public_key: ec.EllipticCurvePublicKey ) -> bytes: """Implements the exchange interface. See :py:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.exchange` for documentationen. Raises: ValueError: If the curves does not match or the decrypt bit isn't set. """ if not self._public.objectAttributes & TPMA_OBJECT.DECRYPT: raise ValueError( "TPM key does not allow ECDH key exchange (object attribute decrypt is not set)" ) if type(peer_public_key.curve) != type(self.curve): raise ValueError( f"curve mismatch for peer key, got {peer_public_key.curve.name}, expected {self.curve.name}" ) scheme = TPMT_SIG_SCHEME(scheme=TPM2_ALG.ECDH) _compare_schemes(scheme, self._public.parameters.eccDetail.scheme) in_point = TPM2B_ECC_POINT() nums = peer_public_key.public_numbers() _int_to_buffer(nums.x, in_point.point.x) _int_to_buffer(nums.y, in_point.point.y) out_point = self._ectx.ecdh_zgen(self._handle, in_point, session1=self._session) return bytes(out_point.point.x) def public_key(self) -> ec.EllipticCurvePublicKey: """Get the public key. Returns: the public part of the ECC key as a :py:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` """ return public_to_key(self._public) def get_digest_algorithm(self) -> hashes.HashAlgorithm: """Get an usable digest algorithm for use with the key. If any scheme with a specified digest algorithm is specified return that algorithm. Otherwise the name digest algorithm is returned. The returned digest algorithm can be used with different cryptography functions. Returns: The digest algorithm as a :py:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` subclass. Raises: ValueError: If the digest algorithm is not supported. """ if self._public.parameters.eccDetail.scheme.scheme == TPM2_ALG.ECDSA: tpm_alg = self._public.parameters.eccDetail.scheme.details.anySig.hashAlg else: tpm_alg = self._public.nameAlg halg = _get_digest(tpm_alg) if halg is None: raise ValueError(f"unsupported digest algorithm {tpm_alg}") return halg def get_signature_algorithm(self) -> ec.EllipticCurveSignatureAlgorithm: """Get a padding configuration for use with the sign method. If the key has a scheme specified, use that scheme. Otherwise, use ECDSA as the default Returns: an instance of :py:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurveSignatureAlgorithm` Raises: ValueError: If the either the scheme or digest algorithm is unsupported. """ if self._public.parameters.eccDetail.scheme.scheme == TPM2_ALG.NULL: scheme = TPMT_ECC_SCHEME(scheme=TPM2_ALG.ECDSA) scheme.details.anySig.hashAlg = self._public.nameAlg else: scheme = self._public.parameters.eccDetail.scheme if scheme.scheme == TPM2_ALG.ECDSA: algorithm = self.get_digest_algorithm() sig_alg = ec.ECDSA(algorithm()) else: raise ValueError(f"unsupported signature scheme {scheme.scheme}") return sig_alg def sign( self, data: bytes, signature_algorithm: ec.EllipticCurveSignatureAlgorithm ) -> bytes: """Implements the sign interface. See :py:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.sign`: for documentation. Raises: ValueError: if the requested signature algorithm isn't supported by the key or the sign_encrypt bit isn't set. """ if not self._public.objectAttributes & TPMA_OBJECT.SIGN_ENCRYPT: raise ValueError( "TPM key does not allow signing (object attribute sign_encrypt is not set)" ) algorithm = signature_algorithm.algorithm if isinstance(algorithm, Prehashed): raise ValueError("Prehashed data is not supported") scheme = TPMT_SIG_SCHEME() _ecc_sign_algorithm_to_scheme(signature_algorithm, scheme) _compare_schemes(scheme, self._public.parameters.eccDetail.scheme) h = hashes.Hash(algorithm) h.update(data) digest = h.finalize() validation = TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL) tpm_sig = self._ectx.sign( self._handle, digest, scheme, validation, session1=self._session ) return bytes(tpm_sig) @property def curve(self) -> ec.EllipticCurve: """The ECC curve.""" return self._curve() @property def key_size(self) -> int: """The ECC key size.""" return self.public_key().key_size def private_numbers(self) -> None: """Always raises a NotImplementedError.""" raise NotImplementedError() def private_bytes( self, encoding: Encoding, format: PrivateFormat, encryption_algorithm: KeySerializationEncryption, ) -> None: """Always raises a NotImplementedError.""" raise NotImplementedError() def __copy__(self) -> "tpm_ecc_private_key": """Returns a shallow copy of the private key.""" return tpm_ecc_private_key( ectx=self._ectx, handle=self._handle, session=self._session ) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/encoding.py000066400000000000000000000627451506405471500213360ustar00rootroot00000000000000from binascii import hexlify, unhexlify from typing import Any, Union, List, Dict from ._libtpm2_pytss import ffi from .constants import ( TPM_FRIENDLY_INT, TPMA_FRIENDLY_INTLIST, TPM2_CAP, TPM2_ST, TPM2_ALG, TPMA_NV, TPMA_CC, TPM2_NT, TPMA_LOCALITY, ) from .types import ( TPM_OBJECT, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM2B_PUBLIC, TPM2B_SENSITIVE, TPMT_PUBLIC, TPMT_SENSITIVE, TPMT_KDF_SCHEME, TPMT_ASYM_SCHEME, TPMT_RSA_SCHEME, TPMT_ECC_SCHEME, TPMT_SYM_DEF_OBJECT, TPMT_KEYEDHASH_SCHEME, TPMT_HA, TPMS_CAPABILITY_DATA, TPMS_ATTEST, TPMT_SIGNATURE, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, TPMT_SYM_DEF, TPMT_SIG_SCHEME, TPMT_RSA_DECRYPT, TPMT_PUBLIC_PARMS, TPM_BASE_OBJECT, ) class base_encdec(object): """Base encoder/decoder for TPM types Args: strict (bool): If a exception should be raised for unknown fields during decoding, defaults to False. case_insensitive (bool): If field names should be case insensitive during decoding, defaults to False. """ def __init__(self, strict: bool = False, case_insensitive: bool = False): self._strict = strict self._case_insensitive = case_insensitive def _is_union(self, val): if not hasattr(val, "_cdata"): return False to = ffi.typeof(val._cdata) if to.kind == "pointer": to = to.item if to.kind == "union": return True return False def _get_complex_field(self, val): for fn in dir(val._cdata): if fn != "size": return getattr(val, fn) return None def _set_complex_field(self, dst, f): for fn in dir(dst._cdata): if fn != "size": setattr(dst, fn, f) return raise ValueError(f"no complex field found for {dst.__class__.__name__}") def _get_element_type(self, dst): return type(dst[0]) def _get_by_selector(self, val, field): if isinstance(val, TPMS_CAPABILITY_DATA): if val.capability == TPM2_CAP.ALGS: return val.data.algorithms if val.capability == TPM2_CAP.HANDLES: return val.data.handles if val.capability == TPM2_CAP.COMMANDS: return val.data.command if val.capability == TPM2_CAP.PP_COMMANDS: return val.data.ppCommands if val.capability == TPM2_CAP.AUDIT_COMMANDS: return val.data.auditCommands if val.capability == TPM2_CAP.PCRS: return val.data.assignedPCR if val.capability == TPM2_CAP.TPM_PROPERTIES: return val.data.tpmProperties if val.capability == TPM2_CAP.PCR_PROPERTIES: return val.data.pcrProperties if val.capability == TPM2_CAP.ECC_CURVES: return val.data.eccCurves elif isinstance(val, TPMS_ATTEST): if val.type == TPM2_ST.ATTEST_CERTIFY: return val.attested.certify if val.type == TPM2_ST.ATTEST_CREATION: return val.attested.creation if val.type == TPM2_ST.ATTEST_QUOTE: return val.attested.quote if val.type == TPM2_ST.ATTEST_COMMAND_AUDIT: return val.attested.commandAudit if val.type == TPM2_ST.ATTEST_SESSION_AUDIT: return val.attested.sessionAudit if val.type == TPM2_ST.ATTEST_TIME: return val.attested.time if val.type == TPM2_ST.ATTEST_NV: return val.attested.nv elif ( isinstance(val, (TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT)) and field == "keyBits" ): if val.algorithm == TPM2_ALG.XOR: return val.keyBits.exclusiveOr elif val.algorithm in (TPM2_ALG.NULL, TPM2_ALG.ERROR): return None return val.keyBits.sym elif isinstance(val, (TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT)) and field == "mode": if val.algorithm in (TPM2_ALG.XOR, TPM2_ALG.NULL, TPM2_ALG.ERROR): return None return val.mode.sym elif isinstance(val, TPMT_KEYEDHASH_SCHEME): if val.scheme == TPM2_ALG.HMAC: return val.details.hmac if val.scheme == TPM2_ALG.XOR: return val.details.exclusiveOr if val.scheme == TPM2_ALG.NULL: return None elif isinstance(val, TPMT_SIG_SCHEME): if val.scheme == TPM2_ALG.ECDAA: return val.details.ecdaa return val.details.any elif isinstance(val, TPMT_KDF_SCHEME): if val.scheme in (TPM2_ALG.NULL, TPM2_ALG.ERROR): return None return val.details.mgf1 elif isinstance( val, (TPMT_ASYM_SCHEME, TPMT_RSA_SCHEME, TPMT_RSA_DECRYPT, TPMT_ECC_SCHEME) ): if val.scheme == TPM2_ALG.ECDAA: return val.details.ecdaa if val.scheme in (TPM2_ALG.RSAES, TPM2_ALG.NULL, TPM2_ALG.ERROR): return None return val.details.anySig elif isinstance(val, TPMT_SIGNATURE): if val.sigAlg in (TPM2_ALG.RSASSA, TPM2_ALG.RSAPSS): return val.signature.rsassa if val.sigAlg in ( TPM2_ALG.ECDSA, TPM2_ALG.ECDAA, TPM2_ALG.SM2, TPM2_ALG.ECSCHNORR, ): return val.signature.ecdsa if val.sigAlg == TPM2_ALG.HMAC: return val.signature.hmac elif ( isinstance(val, (TPMT_PUBLIC_PARMS, TPMT_PUBLIC)) and field == "parameters" ): if val.type == TPM2_ALG.KEYEDHASH: return val.parameters.keyedHashDetail if val.type == TPM2_ALG.SYMCIPHER: return val.parameters.symDetail if val.type == TPM2_ALG.RSA: return val.parameters.rsaDetail if val.type == TPM2_ALG.ECC: return val.parameters.eccDetail elif isinstance(val, TPMT_PUBLIC) and field == "unique": if val.type in (TPM2_ALG.KEYEDHASH, TPM2_ALG.SYMCIPHER): return val.unique.keyedHash if val.type == TPM2_ALG.RSA: return val.unique.rsa if val.type == TPM2_ALG.ECC: return val.unique.ecc elif isinstance(val, TPMT_SENSITIVE): return val.sensitive.any elif isinstance(val, TPMT_HA): return bytes(val) raise ValueError( f"unable to find union selector for field {field} in {val.__class__.__name__}" ) def encode( self, val: Union[ TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT, bytes, ], ) -> Union[int, str, Dict[str, Any], list, None]: """Encode a TPM type Args: val (Union[TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT, bytes]): The value to encode Returns: Union[int, str, dict. list, None] depending on input value. Raises: TypeError: if val is either a TPM union or if type of val is unsupported. """ if isinstance(val, TPM_BASE_OBJECT) and self._is_union(val): raise TypeError(f"tried to encode union {val.__class__.__name__}") if isinstance(val, TPMA_FRIENDLY_INTLIST): return self.encode_friendly_intlist(val) elif isinstance(val, TPM_FRIENDLY_INT): return self.encode_friendly_int(val) elif isinstance(val, int): return self.encode_int(val) elif isinstance(val, TPM2B_SIMPLE_OBJECT): return self.encode_simple_tpm2b(val) elif isinstance( val, ( TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, ), ): return self.encode_complex_tpm2b(val) elif isinstance(val, TPML_OBJECT): return self.encode_tpml(val) elif isinstance(val, TPM_OBJECT): return self.encode_struct(val) elif isinstance(val, bytes): if len(val) == 0: return None return hexlify(val).decode("ascii") raise TypeError(f"unable to encode value of type {val.__class__.__name__}") def encode_int(self, val: int) -> int: """Encode an integer value Args: val (int): The value to encode Returns: The value as an int """ return val def encode_friendly_int(self, val: TPM_FRIENDLY_INT) -> int: """Encode a TPM_FRIENDLY_INT value Args: val (TPM_FRIENDLY_INT): The value to encode Returns: The value as an int """ return int(val) def encode_friendly_intlist(self, val: TPMA_FRIENDLY_INTLIST) -> int: """Encode a TPMA_FRIENDLY_INTLIST value Args: val (TPMA_FRIENDLY_INTLIST): The value to encode Returns: The value as an int """ return int(val) def encode_simple_tpm2b(self, val: TPM2B_SIMPLE_OBJECT) -> Union[str, None]: """Encode a TPM2B_SIMPLE_OBJECT value Args: val (TPM2B_SIMPLE_OBJECT): The value to encode Returns: The value buffer as hex encoded string, or None if empty """ if len(val) == 0: return None return str(val) def encode_complex_tpm2b( self, val: Union[ TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, ], ) -> Dict[str, Any]: """Encode a complex TPM2B object value Args: val (Union[TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA]): The value to encode Returns: The non-size field encoded as a dict """ val = self._get_complex_field(val) return self.encode_struct(val) def encode_tpml(self, val: TPML_OBJECT) -> list: """Encode a TPML_OBJECT value Args: val (TPML_OBJECT): The value to encode Returns: A list with all the elements encoded """ l = list() for v in val: ev = self.encode(v) l.append(ev) return l def encode_pcrselect(self, val: bytes) -> List[int]: """Encode a pcrSelect value Args: val (bytes): The value to encode Returns: A list containing all the set PCRs """ pcrs = [] val = reversed(bytes(val)) si = int.from_bytes(val, "big") for i in range(0, si.bit_length()): b = si >> i if 1 & b: pcrs.append(i) return pcrs def encode_struct(self, val: TPM_OBJECT) -> Dict[str, Any]: """Encode a TPM_OBJECT value Args: val (TPM_OBJECT): The value to encode Returns: A dict containing all the encoded fields """ d = dict() attrs = dir(val._cdata) for a in attrs: av = getattr(val, a) if self._is_union(av): av = self._get_by_selector(val, a) if av is None: continue if a == "pcrSelect" and "sizeofSelect" in attrs: sv = self.encode_pcrselect(av[0 : val.sizeofSelect]) elif a == "sizeofSelect": continue else: sv = self.encode(av) if sv is not None: d[a] = sv if len(d) == 0: return None return d def decode( self, dst: Union[ TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT, ], src: Union[int, str, dict, list], ) -> Union[ TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT, ]: """Decode a value into a TPM type Args: dst (Union[TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT]): The (type) instance to decode into src (Union[int, str, dict, list]): The value to decode Returns: The decoded value as a Union[TPMA_FRIENDLY_INTLIST, TPM_FRIENDLY_INT, int, TPM2B_SIMPLE_OBJECT, TPML_OBJECT, TPM_OBJECT] Raises: TypeError: if dst is not a supported type or dst is a TPM union """ if isinstance(dst, TPM_BASE_OBJECT) and self._is_union(dst): raise TypeError(f"tried to decode union {dst.__class__.__name__}") if isinstance(dst, TPMA_FRIENDLY_INTLIST): return self.decode_friendly_intlist(dst, src) elif isinstance(dst, TPM_FRIENDLY_INT): return self.decode_friendly_int(dst, src) elif isinstance(dst, int): return self.decode_int(dst, src) elif isinstance(dst, TPM2B_SIMPLE_OBJECT): return self.decode_simple_tpm2b(dst, src) elif isinstance( dst, ( TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, ), ): return self.decode_complex_tpm2b(dst, src) elif isinstance(dst, TPML_OBJECT): return self.decode_tpml(dst, src) elif isinstance(dst, TPM_OBJECT): return self.decode_struct(dst, src) raise TypeError(f"unable to decode value of type {dst.__class__.__name__}") def decode_int(self, dst: int, src: int) -> int: """Decode an integer value Args: dst (int): the instance type to encode the integer as src (int): the int value to decode Returns: The int value as them same type as dst """ return type(dst)(src) def decode_friendly_int(self, dst: TPM_FRIENDLY_INT, src: int) -> TPM_FRIENDLY_INT: """Decode a TPM_FRIENDLY_INT value Args: dst (TPM_FRIENDLY_INT): the instance type to encode the integer as src (int): the int value to decode Returns: The int value as them same type as dst """ return type(dst)(src) def decode_friendly_intlist( self, dst: TPMA_FRIENDLY_INTLIST, src: int ) -> TPMA_FRIENDLY_INTLIST: """Decode a TPMA_FRIENDLY_INTLIST value Args: dst (TPMA_FRIENDLY_INTLIST): the instance type to encode the integer as src (int): the int value to decode Returns: The int value as them same type as dst """ return type(dst)(src) def decode_simple_tpm2b( self, dst: TPM2B_SIMPLE_OBJECT, src: str ) -> TPM2B_SIMPLE_OBJECT: """Decode a TPM2B_SIMPLE_OBJECT value Args: dst (TPM2B_SIMPLE_OBJECT): the instance to decode into src (str): the value as a hex encoded string Returns: dst containing the decoded value """ dst.buffer = unhexlify(src) return dst def decode_complex_tpm2b( self, dst: Union[ TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, ], src: Dict[str, Any], ) -> Union[ TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA, ]: """Decode a complex TPM2V value Args: dst (Union[TPM2B_PUBLIC, TPM2B_SENSITIVE_CREATE, TPM2B_ECC_POINT, TPM2B_SENSITIVE, TPM2B_NV_PUBLIC, TPM2B_CREATION_DATA]): The instance to decode into src (dict): The value to decode Returns: dst containing the decoded value """ f = self._get_complex_field(dst) f = self.decode(f, src) self._set_complex_field(dst, f) return dst def decode_tpml(self, dst: TPML_OBJECT, src: list) -> TPML_OBJECT: """Decode a TPML_OBJECT value Args: dst (TPML_OBJECT): The TPML_OBJECT to decode into src (list): the list of values to decode Returns: dst containing the decoded elements """ ec = self._get_element_type(dst) i = 0 for v in src: e = ec() e = self.decode(e, v) dst[i] = e i = i + 1 return dst def decode_pcrselect(self, dst: bytes, src: List[int]) -> bytes: """Decode a pctSelect value Args: dst (bytes): the pcrSelect value, currently ignored src (List[int]): a list of the selected PCRs Returns: bytes with the selected PCR bits set """ pcrs = 0 for pcr in src: pcrs = pcrs | (1 << pcr) return bytes(reversed(pcrs.to_bytes(4, "big"))).rstrip(b"\x00") def decode_struct(self, dst: TPM_OBJECT, src: Dict[str, Any]) -> TPM_OBJECT: """Decode a TPM_OBJECT value Args: dst (TPM_OBJECT): The TPM_OBJECT instance to decode into src (dict): A dict of fields/values to decode Returns: dst containing the decoded values Raises: ValueError if strict is True and src containings unknown fields """ if self._case_insensitive: fm = [(x.lower(), x) for x in dir(dst._cdata)] fields = dict(fm) km = [(x.lower(), x) for x in src.keys()] keys = dict(km) else: fm = [(x, x) for x in dir(dst._cdata)] fields = dict(fm) km = [(x, x) for x in src.keys()] keys = dict(km) mkeys = [x for x in keys if x in fields] if self._strict: missing = [x for x in keys if x not in fields] if len(missing) > 0: raise ValueError(f"unknown field(s) {', '.join(missing)} in source") for k in mkeys: rk = keys[k] rf = fields[k] df = getattr(dst, rf) if self._is_union(df): df = self._get_by_selector(dst, rf) rdst = df else: rdst = dst sf = src[rk] if rf == "pcrSelect" and "sizeofSelect" in fields.values(): dv = self.decode_pcrselect(df, sf) setattr(rdst, "sizeofSelect", len(dv)) elif rf == "sizeofSelect" and "pcrSelect" in fields.values(): continue else: dv = self.decode(df, sf) setattr(rdst, rk, dv) return dst class json_encdec(base_encdec): """Encode TPM types according to TCG TSS 2.0 JSON Data Types and Policy Language Specification Args: strict (bool): If a exception should be raised for unknown fields during decoding, defaults to True. case_insensitive (bool): If field names should be case insensitive during decoding, defaults to True. """ def __init__(self, strict=True, case_insensitive=True): super().__init__(strict=strict, case_insensitive=case_insensitive) def encode_int(self, val: int) -> Union[List[int], int]: """Encode an int value Args: val (int): The value to encode Returns: An int or a list of two ints if size is over 54 bit """ if val >= 0x100000000: return [(val >> 32) & 0xFFFFFFFF, val & 0xFFFFFFFF] return int(val) def encode_friendly_int(self, val: TPM_FRIENDLY_INT) -> Union[str, int, List[int]]: """Encode a TPM_FRIENDLY_INT value Args: val (TPM_FRIENDLY_INT): The value to encode Returns: A str if the val matches a constant, otherwise an encoded int """ if isinstance(val, TPM_FRIENDLY_INT) and val in type(val): return str(val) return self.encode_int(val) def encode_friendly_intlist(self, val: TPMA_FRIENDLY_INTLIST) -> Dict[str, int]: """Encode a TPMA_FRIENDLY_INTLIST valut Args: val (TPMA_FRIENDLY_INT): The value to encode Returns A dict with the attribute names as the key and 1 as the value """ attrs = dict() for i in range(0, 32): c = val & (1 << i) if c in type(val) and c != 0: k = str(c) attrs[k] = 1 if isinstance(val, TPMA_NV) and val.nt: attrs["nt"] = self.encode_friendly_int(val.nt) if isinstance(val, TPMA_CC) and val.commandindex: attrs["commandindex"] = val.commandindex if isinstance(val, TPMA_CC) and val.chandles: attrs["chandles"] = val.chandles if isinstance(val, TPMA_LOCALITY) and val > 31: attrs["extended"] = ( val & TPMA_LOCALITY.EXTENDED_MASK ) >> TPMA_LOCALITY.EXTENDED_SHIFT return attrs def decode_int(self, dst: int, src: Union[int, str, List[int]]) -> int: """Decode an int value Args: dst (int): The int instance, currently ignored src (Union[int, str, List[int]]): An int, a string containing the hex encoded value or a list of two ints Returns: A decoded int """ if isinstance(src, str): dst = int(src, base=0) elif isinstance(src, list): dst = src[0] << 32 | src[1] else: dst = int(src) return dst def decode_friendly_int( self, dst: TPM_FRIENDLY_INT, src: Union[int, str] ) -> TPM_FRIENDLY_INT: """Decode a TPM_FRIENDLY_INT Args: dst (TPM_FRIENDLY_INT): The instance which type will be used src (Union[str, int]): Either a string containing the name of a constant or an int Returns: An instance of the same type as dst containing the decoded value """ p = dst.__class__.__name__.lower() + "_" if isinstance(src, str): src = src.lower() if src.startswith(p): src = src[len(p)] try: return type(dst).parse(src) except (TypeError, ValueError): pass v = self.decode_int(dst, src) return type(dst)(v) def decode_friendly_intlist( self, dst: TPMA_FRIENDLY_INTLIST, src: Union[Dict[str, Any], List[str]] ) -> TPMA_FRIENDLY_INTLIST: """Decode a TPMA_FRIENDLY_INTLIST value Args: dst (TPMA_FRIENDLY_INTLIST): The instance which type will be used src (Union[Dict[str, Any], List[str]]): Either a dict with the attribute name as the key or a list of attributes Returns: An instance of the same type as dst containing the decoded value """ attrs = type(dst)() p = dst.__class__.__name__.lower() + "_" if isinstance(src, dict): for k, v in src.items(): k = k.lower() if k.startswith(p): k = k[len(p) :] if isinstance(dst, TPMA_NV) and k == "nt": nt = self.decode_friendly_int(TPM2_NT(), v) attrs = attrs | nt << TPMA_NV.TPM2_NT_SHIFT continue elif isinstance(dst, TPMA_CC) and k == "commandindex": commandindex = self.decode_int(int(), v) attrs = attrs | commandindex continue elif isinstance(dst, TPMA_CC) and k == "chandles": chandles = self.decode_int(int(), v) attrs = attrs | chandles << TPMA_CC.CHANDLES_SHIFT continue elif isinstance(dst, TPMA_LOCALITY) and k == "extended": extended = self.decode_int(int(), v) attrs = attrs | extended << TPMA_LOCALITY.EXTENDED_SHIFT continue a = type(dst).parse(k) if (isinstance(v, str) and v.lower() in ("clear", "no")) or not v: attrs = attrs & ~a else: attrs = attrs | a elif isinstance(src, list): for v in src: v = v.lower() if v.startswith(p): v = v[len(p) :] a = type(dst).parse(v) attrs = attrs | a else: attrs = self.decode_int(dst, src) return attrs def decode_simple_tpm2b(self, dst, src): """Decode a TPM2B_SIMPLE_OBJECT value Args: dst (TPM2B_SIMPLE_OBJECT): The object to store the decoded value in src (Union[str, List[int]]): Either a hex encoded string or a list of integers Returns: dst containing the decoded value """ if isinstance(src, list): dst.buffer = bytes(src) return dst if src[0:2] == "0x": src = src[2:] dst.buffer = unhexlify(src) return dst tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/fapi_info.py000066400000000000000000000127711506405471500214740ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2-Clause # Copyright (c) 2020 Johannes Holland # All rights reserved. """Interface to make TPM info dict structure more accessible via dot notation.""" from collections import defaultdict class Traversable: """Attributes are traversable recursively.""" def __init__(self, data): self.data = data def __str__(self): return str(self.data) def attrs_recursive(self, parent=""): """Return a generator to all attributes.""" attrs_rec = [] sep = "." if parent else "" for attr in dir(self): attr = attr.replace("-", "_") child = getattr(self, attr) if isinstance(child, Traversable): attrs_rec.extend(child.attrs_recursive(parent=f"{parent}{sep}{attr}")) else: attrs_rec.append(f"{parent}{sep}{attr}") yield from attrs_rec class BasicDict(Traversable): """Takes a dict and makes values accessible via dot notation.""" def __getattr__(self, attr): return self.data[attr] def __dir__(self): return self.data.keys() class NamedKVPList(Traversable): """ Takes a list of KVPs where both key and value are named (i.e. KVPs itself), e.g. [ { "property": "VENDOR_TPM_TYPE", "value": 1 }, { "property": "FIRMWARE_VERSION_1", "value": 538513443 } ] Makes the values accessible via dot notation. If a value_class is given, an instance of that class is returned (passing the value to __init__()). """ def __init__(self, data, key_name, value_name, value_class=None): super().__init__(data) self.key_name = key_name self.value_name = value_name self.value_class = value_class def __getattr__(self, attr): value = next( item[self.value_name] for item in self.data if item[self.key_name].lower() == attr.lower() ) if self.value_class: return self.value_class(value) return value def __dir__(self): return [item[self.key_name].lower() for item in self.data] class Capabilities(Traversable): """Takes a list of capability dicts and makes them accessible via dot notation.""" def _get_cap_data(self, description): return next(cap for cap in self.data if cap["description"] == description)[ "info" ]["data"] def __getattr__(self, attr): # some caps are accessed via '_' but their names contain '-' attr = attr.replace("_", "-") cap_data = self._get_cap_data(attr) cap = defaultdict( lambda: cap_data, { "algorithms": NamedKVPList( cap_data, "alg", "algProperties", value_class=globals()["BasicDict"] ), "properties-fixed": NamedKVPList(cap_data, "property", "value"), "properties-variable": NamedKVPList(cap_data, "property", "value"), "commands": None, # TODO by command index? "pcrs": NamedKVPList(cap_data, "hash", "pcrSelect"), "pcr-properties": NamedKVPList(cap_data, "tag", "pcrSelect"), }, )[attr] return cap def __dir__(self): return [item["description"] for item in self.data] def str_from_int_list(int_list): """Cast integers to bytes and decode as string.""" string = b"".join( integer.to_bytes(4, byteorder="big") for integer in int_list ).decode("utf-8") # remove leading or trailing whitespaces string = string.strip() # remove null bytes string = string.replace("\x00", "") # replace multiple whitespaces with a single one string = " ".join(string.split()) return string class FapiInfo(Traversable): """Takes a FAPI info dict and and makes its values accessible via dot notation.""" def __getattr__(self, attr): item_data = self.data[attr] return defaultdict( lambda: item_data, { "fapi_config": BasicDict(item_data), "capabilities": Capabilities(item_data), }, )[attr] @property def vendor_string(self): """Get the TPM Vendor String.""" return str_from_int_list( [ self.capabilities.properties_fixed.vendor_string_1, self.capabilities.properties_fixed.vendor_string_2, self.capabilities.properties_fixed.vendor_string_3, self.capabilities.properties_fixed.vendor_string_4, ] ) @property def manufacturer(self): """Get the TPM Manufacturer.""" return str_from_int_list([self.capabilities.properties_fixed.manufacturer]) @property def firmware_version(self): """Get the TPM Firmware Version (formatted according to vendor conventions).""" key = f"{self.manufacturer}.{self.vendor_string}" ver1 = self.capabilities.properties_fixed.firmware_version_1 ver2 = self.capabilities.properties_fixed.firmware_version_2 return defaultdict( lambda: f"{ver1:x}.{ver2:x}", {"IBM.SW TPM": f"{ver1:x}.{ver2:x}"} )[key] @property def spec_revision(self): """Get the TPM Specification Revision.""" rev = self.capabilities.properties_fixed.ps_revision # Add '.' after first digit rev = f"{rev // 100}.{rev % 100}" return rev def __dir__(self): return self.data.keys() tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/internal/000077500000000000000000000000001506405471500207745ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/internal/__init__.py000066400000000000000000000000001506405471500230730ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/internal/crypto.py000066400000000000000000000555151506405471500227010ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from math import ceil from ..constants import TPM2_ALG, TPM2_ECC from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding from cryptography.hazmat.primitives.asymmetric.utils import ( encode_dss_signature, Prehashed, ) from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.hmac import HMAC from cryptography.hazmat.primitives.serialization import ( load_pem_private_key, load_der_private_key, load_pem_public_key, load_der_public_key, load_ssh_public_key, load_ssh_private_key, Encoding, PublicFormat, ) from cryptography.x509 import load_pem_x509_certificate, load_der_x509_certificate from cryptography.hazmat.primitives.kdf.kbkdf import CounterLocation, KBKDFHMAC, Mode from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash from cryptography.hazmat.primitives.ciphers.algorithms import AES, Camellia, SM4 from cryptography.hazmat.primitives.ciphers import modes, Cipher, CipherAlgorithm from cryptography.hazmat.backends import default_backend from cryptography.exceptions import UnsupportedAlgorithm, InvalidSignature from typing import Tuple, Type, Any import secrets import inspect _curvetable = ( (TPM2_ECC.NIST_P192, ec.SECP192R1), (TPM2_ECC.NIST_P224, ec.SECP224R1), (TPM2_ECC.NIST_P256, ec.SECP256R1), (TPM2_ECC.NIST_P384, ec.SECP384R1), (TPM2_ECC.NIST_P521, ec.SECP521R1), ) _digesttable = ( (TPM2_ALG.SHA1, hashes.SHA1), (TPM2_ALG.SHA256, hashes.SHA256), (TPM2_ALG.SHA384, hashes.SHA384), (TPM2_ALG.SHA512, hashes.SHA512), (TPM2_ALG.SHA3_256, hashes.SHA3_256), (TPM2_ALG.SHA3_384, hashes.SHA3_384), (TPM2_ALG.SHA3_512, hashes.SHA3_512), (TPM2_ALG.SM3_256, hashes.SM3), ) _algtable = ( (TPM2_ALG.AES, AES), (TPM2_ALG.CAMELLIA, Camellia), (TPM2_ALG.CFB, modes.CFB), (TPM2_ALG.SM4, SM4), ) def _get_curveid(curve): for algid, c in _curvetable: if isinstance(curve, c): return algid return None def _get_curve(curveid): for algid, c in _curvetable: if algid == curveid: return c return None def _get_digest(digestid): for algid, d in _digesttable: if algid == digestid: return d return None def _get_pyca_digest(digest_type): for algid, d in _digesttable: if inspect.isclass(digest_type) and issubclass(digest_type, d): return algid elif isinstance(digest_type, d): return algid return None def _get_alg(alg): for algid, a in _algtable: if algid == alg: return a return None def _int_to_buffer(i, b): s = ceil(i.bit_length() / 8) b.buffer = i.to_bytes(length=s, byteorder="big") def key_from_encoding(data, password=None): try: cert = load_pem_x509_certificate(data, backend=default_backend()) key = cert.public_key() return key except ValueError: pass try: key = load_pem_public_key(data, backend=default_backend()) return key except ValueError: pass try: pkey = load_pem_private_key(data, password=password, backend=default_backend()) key = pkey.public_key() return key except ValueError: pass try: key = load_ssh_public_key(data, backend=default_backend()) return key except (ValueError, UnsupportedAlgorithm): pass try: cert = load_der_x509_certificate(data, backend=default_backend()) key = cert.public_key() return key except ValueError: pass try: key = load_der_public_key(data, backend=default_backend()) return key except ValueError: pass try: pkey = load_der_private_key(data, password=password, backend=default_backend()) key = pkey.public_key() return key except ValueError: pass raise ValueError("Unsupported key format") def _public_from_encoding(data, obj, password=None): key = key_from_encoding(data, password) nums = key.public_numbers() if isinstance(key, rsa.RSAPublicKey): obj.type = TPM2_ALG.RSA obj.parameters.rsaDetail.keyBits = key.key_size _int_to_buffer(nums.n, obj.unique.rsa) if nums.e != 65537: obj.parameters.rsaDetail.exponent = nums.e else: obj.parameters.rsaDetail.exponent = 0 elif isinstance(key, ec.EllipticCurvePublicKey): obj.type = TPM2_ALG.ECC curveid = _get_curveid(key.curve) if curveid is None: raise ValueError(f"unsupported curve: {key.curve.name}") obj.parameters.eccDetail.curveID = curveid _int_to_buffer(nums.x, obj.unique.ecc.x) _int_to_buffer(nums.y, obj.unique.ecc.y) else: raise ValueError(f"unsupported key type: {key.__class__.__name__}") def private_key_from_encoding(data, password=None): try: key = load_pem_private_key(data, password=password, backend=default_backend()) return key except ValueError: pass try: key = load_ssh_private_key(data, password=password, backend=default_backend()) return key except ValueError: pass try: key = load_der_private_key(data, password=password, backend=default_backend()) return key except ValueError: pass raise ValueError("Unsupported key format") def _private_from_encoding(data, obj, password=None): key = private_key_from_encoding(data, password) nums = key.private_numbers() if isinstance(key, rsa.RSAPrivateKey): obj.sensitiveType = TPM2_ALG.RSA _int_to_buffer(nums.p, obj.sensitive.rsa) elif isinstance(key, ec.EllipticCurvePrivateKey): obj.sensitiveType = TPM2_ALG.ECC _int_to_buffer(nums.private_value, obj.sensitive.ecc) else: raise ValueError(f"unsupported key type: {key.__class__.__name__}") def public_to_key(obj): key = None if obj.type == TPM2_ALG.RSA: b = obj.unique.rsa.buffer n = int.from_bytes(b, byteorder="big") e = obj.parameters.rsaDetail.exponent if e == 0: e = 65537 nums = rsa.RSAPublicNumbers(e, n) key = nums.public_key(backend=default_backend()) elif obj.type == TPM2_ALG.ECC: curve = _get_curve(obj.parameters.eccDetail.curveID) if curve is None: raise ValueError(f"unsupported curve: {obj.parameters.eccDetail.curveID}") x = int.from_bytes(obj.unique.ecc.x, byteorder="big") y = int.from_bytes(obj.unique.ecc.y, byteorder="big") nums = ec.EllipticCurvePublicNumbers(x, y, curve()) key = nums.public_key(backend=default_backend()) else: raise ValueError(f"unsupported key type: {obj.type}") return key class _MyRSAPrivateNumbers: def __init__(self, p: int, n: int, e: int, pubnums: rsa.RSAPublicNumbers): q = n // p d = _MyRSAPrivateNumbers._generate_d(p, q, e, n) dmp1 = rsa.rsa_crt_dmp1(d, p) dmq1 = rsa.rsa_crt_dmq1(d, q) iqmp = rsa.rsa_crt_iqmp(p, q) self._private_numbers = rsa.RSAPrivateNumbers( p, q, d, dmp1, dmq1, iqmp, pubnums ) def private_key(self, *args: Any, **kwargs: Any) -> rsa.RSAPrivateKey: return self._private_numbers.private_key(*args, **kwargs) @staticmethod def _xgcd(a: int, b: int) -> Tuple[int, int, int]: """return (g, x, y) such that a*x + b*y = g = gcd(a, b)""" x0, x1, y0, y1 = 0, 1, 1, 0 while a != 0: (q, a), b = divmod(b, a), a y0, y1 = y1, y0 - q * y1 x0, x1 = x1, x0 - q * x1 return b, x0, y0 # # The _modinv and _xgcd routines come from the link below. Minor modifications to add an underscore to the names as well # as to check the version of Python and use pow() for modular inverse (since 3.8). # were made. They are licensed under https://creativecommons.org/licenses/by-sa/3.0/ # - https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm#Iterative_algorithm_3 # @staticmethod def _modinv(a, m): return pow(a, -1, m) @staticmethod def _generate_d(p, q, e, n): # P most always be larger so we don't go negative if p < q: p, q = q, p phi = (p - 1) * (q - 1) d = _MyRSAPrivateNumbers._modinv(e, phi) return d def private_to_key(private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC"): key = None if private.sensitiveType == TPM2_ALG.RSA: p = int.from_bytes(bytes(private.sensitive.rsa), byteorder="big") n = int.from_bytes(bytes(public.unique.rsa), byteorder="big") e = ( public.parameters.rsaDetail.exponent if public.parameters.rsaDetail.exponent != 0 else 65537 ) key = _MyRSAPrivateNumbers(p, n, e, rsa.RSAPublicNumbers(e, n)).private_key( backend=default_backend() ) elif private.sensitiveType == TPM2_ALG.ECC: curve = _get_curve(public.parameters.eccDetail.curveID) if curve is None: raise ValueError( f"unsupported curve: {public.parameters.eccDetail.curveID}" ) p = int.from_bytes(bytes(private.sensitive.ecc), byteorder="big") x = int.from_bytes(bytes(public.unique.ecc.x), byteorder="big") y = int.from_bytes(bytes(public.unique.ecc.y), byteorder="big") key = ec.EllipticCurvePrivateNumbers( p, ec.EllipticCurvePublicNumbers(x, y, curve()) ).private_key(backend=default_backend()) else: raise ValueError(f"unsupported key type: {private.sensitiveType}") return key def _public_to_pem(obj, encoding="pem"): encoding = encoding.lower() key = public_to_key(obj) if encoding == "pem": return key.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo) elif encoding == "der": return key.public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo) elif encoding == "ssh": return key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) else: raise ValueError(f"unsupported encoding: {encoding}") def _getname(obj): dt = _get_digest(obj.nameAlg) if dt is None: raise ValueError(f"unsupported digest algorithm: {obj.nameAlg}") d = hashes.Hash(dt(), backend=default_backend()) mb = obj.marshal() d.update(mb) b = d.finalize() db = obj.nameAlg.to_bytes(length=2, byteorder="big") name = db + b return name def _kdfa(hashAlg, key, label, contextU, contextV, bits): halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm: {hashAlg}") if bits % 8: raise ValueError(f"bad key length {bits}, not a multiple of 8") klen = int(bits / 8) context = contextU + contextV kdf = KBKDFHMAC( algorithm=halg(), mode=Mode.CounterMode, length=klen, rlen=4, llen=4, location=CounterLocation.BeforeFixed, label=label, context=context, fixed=None, backend=default_backend(), ) return kdf.derive(key) def kdfe(hashAlg, z, use, partyuinfo, partyvinfo, bits): halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm: {hashAlg}") if bits % 8: raise ValueError(f"bad key length {bits}, not a multiple of 8") klen = int(bits / 8) otherinfo = use + partyuinfo + partyvinfo kdf = ConcatKDFHash( algorithm=halg(), length=klen, otherinfo=otherinfo, backend=default_backend() ) return kdf.derive(z) def _symdef_to_crypt(symdef): alg = _get_alg(symdef.algorithm) if alg is None: raise ValueError(f"unsupported symmetric algorithm {symdef.algorithm}") mode = _get_alg(symdef.mode.sym) if mode is None: raise ValueError(f"unsupported symmetric mode {symdef.mode.sym}") bits = symdef.keyBits.sym return (alg, mode, bits) def _calculate_sym_unique(nameAlg, secret, seed): dt = _get_digest(nameAlg) if dt is None: raise ValueError(f"unsupported digest algorithm: {nameAlg}") d = hashes.Hash(dt(), backend=default_backend()) d.update(seed) d.update(secret) return d.finalize() def _get_digest_size(alg): dt = _get_digest(alg) if dt is None: raise ValueError(f"unsupported digest algorithm: {alg}") return dt.digest_size def _get_signature_bytes(sig): if sig.sigAlg in (TPM2_ALG.RSAPSS, TPM2_ALG.RSASSA): rb = bytes(sig.signature.rsapss.sig) elif sig.sigAlg == TPM2_ALG.ECDSA: r = int.from_bytes(sig.signature.ecdsa.signatureR, byteorder="big") s = int.from_bytes(sig.signature.ecdsa.signatureS, byteorder="big") rb = encode_dss_signature(r, s) elif sig.sigAlg == TPM2_ALG.HMAC: rb = bytes(sig.signature.hmac) else: raise TypeError(f"unsupported signature algorithm: {sig.sigAlg}") return rb def verify_signature_rsa(signature, key, data, prehashed): dt = _get_digest(signature.signature.any.hashAlg) if dt is None: raise ValueError( f"unsupported digest algorithm: {signature.signature.rsapss.hash}" ) mpad = None if signature.sigAlg == TPM2_ALG.RSASSA: pad = padding.PKCS1v15() elif signature.sigAlg == TPM2_ALG.RSAPSS: pad = padding.PSS(mgf=padding.MGF1(dt()), salt_length=dt.digest_size) mpad = padding.PSS(mgf=padding.MGF1(dt()), salt_length=padding.PSS.MAX_LENGTH) else: raise ValueError(f"unsupported RSA signature algorithm: {signature.sigAlg}") if prehashed: digalg = Prehashed(dt()) else: digalg = dt() sig = bytes(signature.signature.rsapss.sig) try: key.verify(sig, data, pad, digalg) except InvalidSignature: if mpad: key.verify(sig, data, mpad, digalg) else: raise def verify_signature_ecc(signature, key, data, prehashed): dt = _get_digest(signature.signature.any.hashAlg) if dt is None: raise ValueError( f"unsupported digest algorithm: {signature.signature.ecdsa.hash}" ) if prehashed: digalg = Prehashed(dt()) else: digalg = dt() r = int.from_bytes(signature.signature.ecdsa.signatureR, byteorder="big") s = int.from_bytes(signature.signature.ecdsa.signatureS, byteorder="big") sig = encode_dss_signature(r, s) key.verify(sig, data, ec.ECDSA(digalg)) def verify_signature_hmac(signature, key, data, prehashed): dt = _get_digest(signature.signature.hmac.hashAlg) if dt is None: raise ValueError( f"unsupported digest algorithm: {signature.signature.hmac.hashAlg}" ) if prehashed: hdata = data else: sh = hashes.Hash(dt(), backend=default_backend()) sh.update(data) hdata = sh.finalize() sig = bytes(signature.signature.hmac) h = HMAC(key, dt(), backend=default_backend()) h.update(hdata) h.verify(sig) def _verify_signature(signature, key, data, prehashed=False): if hasattr(key, "publicArea"): key = key.publicArea kt = getattr(key, "type", None) if kt in (TPM2_ALG.RSA, TPM2_ALG.ECC): key = public_to_key(key) if signature.sigAlg in (TPM2_ALG.RSASSA, TPM2_ALG.RSAPSS): if not isinstance(key, rsa.RSAPublicKey): raise ValueError( f"bad key type for {signature.sigAlg}, expected RSA public key, got {key.__class__.__name__}" ) verify_signature_rsa(signature, key, data, prehashed) elif signature.sigAlg == TPM2_ALG.ECDSA: if not isinstance(key, ec.EllipticCurvePublicKey): raise ValueError( f"bad key type for {signature.sigAlg}, expected ECC public key, got {key.__class__.__name__}" ) verify_signature_ecc(signature, key, data, prehashed) elif signature.sigAlg == TPM2_ALG.HMAC: if not isinstance(key, bytes): raise ValueError( f"bad key type for {signature.sigAlg}, expected bytes, got {key.__class__.__name__}" ) verify_signature_hmac(signature, key, data, prehashed) else: raise ValueError(f"unsupported signature algorithm: {signature.sigAlg}") def _generate_rsa_seed( key: rsa.RSAPublicKey, hashAlg: int, label: bytes ) -> Tuple[bytes, bytes]: halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm {hashAlg}") seed = secrets.token_bytes(halg.digest_size) mgf = padding.MGF1(halg()) padd = padding.OAEP(mgf, halg(), label) enc_seed = key.encrypt(seed, padd) return (seed, enc_seed) def _generate_ecc_seed( key: ec.EllipticCurvePublicKey, hashAlg: int, label: bytes ) -> Tuple[bytes, bytes]: halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm {hashAlg}") ekey = ec.generate_private_key(key.curve, default_backend()) epubnum = ekey.public_key().public_numbers() plength = ceil(key.curve.key_size / 8) exbytes = epubnum.x.to_bytes(plength, "big") eybytes = epubnum.y.to_bytes(plength, "big") # workaround marshal of TPMS_ECC_POINT secret = ( len(exbytes).to_bytes(length=2, byteorder="big") + exbytes + len(eybytes).to_bytes(length=2, byteorder="big") + eybytes ) shared_key = ekey.exchange(ec.ECDH(), key) pubnum = key.public_numbers() xbytes = pubnum.x.to_bytes(plength, "big") seed = kdfe(hashAlg, shared_key, label, exbytes, xbytes, halg.digest_size * 8) return (seed, secret) def _generate_seed(public: "types.TPMT_PUBLIC", label: bytes) -> Tuple[bytes, bytes]: key = public_to_key(public) if public.type == TPM2_ALG.RSA: return _generate_rsa_seed(key, public.nameAlg, label) elif public.type == TPM2_ALG.ECC: return _generate_ecc_seed(key, public.nameAlg, label) else: raise ValueError(f"unsupported seed algorithm {public.type}") def __rsa_secret_to_seed(key, hashAlg: int, label: bytes, outsymseed: bytes): halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm {hashAlg}") mgf = padding.MGF1(halg()) padd = padding.OAEP(mgf, halg(), label) seed = key.decrypt(bytes(outsymseed), padd) return seed def __ecc_secret_to_seed( key: ec.EllipticCurvePrivateKey, hashAlg: int, label: bytes, outsymseed: bytes ) -> Tuple[bytes, bytes]: halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm {hashAlg}") # Get the peer public key (outsymseed) # workaround unmarshal of TPMS_ECC_POINT (we cant use types here do to cyclic deps xlen = int.from_bytes(outsymseed[0:2], byteorder="big") ylen = int.from_bytes(outsymseed[xlen + 2 : xlen + 4], byteorder="big") if xlen + ylen != len(outsymseed) - 4: raise ValueError( f"Expected TPMS_ECC_POINT to have two points of len {xlen + ylen}, got: {len(outsymseed)}" ) exbytes = outsymseed[2 : 2 + xlen] eybytes = outsymseed[xlen + 4 : xlen + 4 + ylen] x = int.from_bytes(exbytes, byteorder="big") y = int.from_bytes(eybytes, byteorder="big") nums = ec.EllipticCurvePublicNumbers(x, y, key.curve) peer_public_key = nums.public_key(backend=default_backend()) shared_key = key.exchange(ec.ECDH(), peer_public_key) pubnum = key.public_key().public_numbers() xbytes = pubnum.x.to_bytes(key.key_size // 8, "big") seed = kdfe(hashAlg, shared_key, label, exbytes, xbytes, halg.digest_size * 8) return seed def _secret_to_seed( private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC", label: bytes, outsymseed: bytes, ): key = private_to_key(private, public) if isinstance(key, rsa.RSAPrivateKey): return __rsa_secret_to_seed(key, public.nameAlg, label, outsymseed) elif isinstance(key, ec.EllipticCurvePrivateKey): return __ecc_secret_to_seed(key, public.nameAlg, label, outsymseed) else: raise ValueError(f"unsupported seed algorithm {public.type}") def _hmac( halg: hashes.HashAlgorithm, hmackey: bytes, enc_cred: bytes, name: bytes ) -> bytes: h = HMAC(hmackey, halg(), backend=default_backend()) h.update(enc_cred) h.update(name) return h.finalize() def _check_hmac( halg: hashes.HashAlgorithm, hmackey: bytes, enc_cred: bytes, name: bytes, expected: bytes, ): h = HMAC(hmackey, halg(), backend=default_backend()) h.update(enc_cred) h.update(name) h.verify(expected) def _encrypt( cipher: Type[CipherAlgorithm], mode: Type[modes.Mode], key: bytes, data: bytes ) -> bytes: iv = len(key) * b"\x00" ci = cipher(key) ciph = Cipher(ci, mode(iv), backend=default_backend()) encr = ciph.encryptor() encdata = encr.update(data) + encr.finalize() return encdata def _decrypt( cipher: Type[CipherAlgorithm], mode: Type[modes.Mode], key: bytes, data: bytes ) -> bytes: iv = len(key) * b"\x00" ci = cipher(key) ciph = Cipher(ci, mode(iv), backend=default_backend()) decr = ciph.decryptor() plaintextdata = decr.update(data) + decr.finalize() return plaintextdata def _rsa_decrypt_padding_to_scheme( decrypt_padding: padding.AsymmetricPadding, scheme: "TPMT_RSA_DECRYPT" ): if isinstance(decrypt_padding, padding.OAEP): if hasattr(decrypt_padding, "algorithm"): alg = decrypt_padding.algorithm else: raise ValueError("unable to get hash algorithm from OAEP padding") scheme.scheme = TPM2_ALG.OAEP halg = _get_pyca_digest(alg) if halg is None: raise ValueError(f"unsupported digest algorithm {alg}") scheme.details.oaep.hashAlg = halg elif isinstance(decrypt_padding, padding.PKCS1v15): scheme.scheme = TPM2_ALG.RSAES else: raise ValueError(f"unsupported RSA decryption scheme: {decrypt_padding}") return def _rsa_sign_padding_to_scheme( sign_padding: padding.AsymmetricPadding, algorithm: hashes.HashAlgorithm, scheme: "TPMT_SIG_SCHEME", ): if isinstance(sign_padding, padding.PSS): scheme.scheme = TPM2_ALG.RSAPSS elif isinstance(sign_padding, padding.PKCS1v15): scheme.scheme = TPM2_ALG.RSASSA else: raise ValueError(f"unsupported RSA signature scheme: {sign_padding}") halg = _get_pyca_digest(algorithm) if halg is None: raise ValueError(f"unsupported digest algorithm {algorithm}") scheme.details.any.hashAlg = halg return def _ecc_sign_algorithm_to_scheme( sign_alg: ec.EllipticCurveSignatureAlgorithm, scheme: "TPMT_SIG_SCHEME" ): if isinstance(sign_alg, ec.ECDSA): scheme.scheme = TPM2_ALG.ECDSA algorithm = sign_alg.algorithm else: raise ValueError(f"unsupported ECC signature scheme: {sign_alg}") halg = _get_pyca_digest(type(algorithm)) if halg is None: raise ValueError(f"unsupported digest algorithm {algorithm}") scheme.details.any.hashAlg = halg return tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/internal/templates.py000066400000000000000000000216211506405471500233460ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from ..types import ( TPMT_SYM_DEF_OBJECT, TPMU_SYM_KEY_BITS, TPMU_SYM_MODE, TPM2B_PUBLIC, TPMT_PUBLIC, TPMU_PUBLIC_PARMS, TPMS_RSA_PARMS, TPMT_RSA_SCHEME, TPMU_PUBLIC_ID, TPMS_ECC_PARMS, TPMT_ECC_SCHEME, TPMT_KDF_SCHEME, TPMS_ECC_POINT, TPM2_HANDLE, ) from ..constants import ( TPM2_ALG, TPMA_OBJECT, TPM2_ECC, ) from typing import ClassVar, Optional, Sequence class template_attributes: low = ( TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.ADMINWITHPOLICY | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT ) high = ( TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.ADMINWITHPOLICY | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT ) class template_policy: low = b"\x83q\x97gD\x84\xb3\xf8\x1a\x90\xcc\x8dF\xa5\xd7$\xfdR\xd7n\x06R\x0bd\xf2\xa1\xda\x1b3\x14i\xaa" sha256 = b"\xca=\n\x99\xa2\xb99\x06\xf7\xa34$\x14\xef\xcf\xb3\xa3\x85\xd4L\xd1\xfdE\x90\x89\xd1\x9bPq\xc0\xb7\xa0" sha384 = b"\xb2n}(\xd1\x1aP\xbcS\xd8\x82\xbc\xf5\xfd:\x1a\x07AH\xbb5\xd3\xb4\xe4\xcb\x1c\n\xd9\xbd\xe4\x19\xca\xcbG\xba\ti\x96F\x15\x0f\x9f\xc0\x00\xf3\xf8\x0e\x12" sha512 = b'\xb8"\x1c\xa6\x9e\x85P\xa4\x91M\xe3\xfa\xa6\xa1\x8c\x07,\xc0\x12\x08\x07:\x92\x8d]f\xd5\x9e\xf7\x9eI\xa4)\xc4\x1ak&\x95q\xd5~\xdb%\xfb\xdb\x188BV\x08\xb4\x13\xcdaj_m\xb5\xb6\x07\x1a\xf9\x9b\xea' sm3_256 = b"\x16x`\xa3_,\\5g\xf9\xc9'\xacV\xc02\xf3\xb3\xa6F/\x8d\x03y\x98\xe7\xa1\x0fw\xfaEJ" class template_symmetric: low = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) aes256 = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) sm4 = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.SM4, keyBits=TPMU_SYM_KEY_BITS(sm4=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) class ek_template: cert_index: ClassVar[TPM2_HANDLE] nonce_index: ClassVar[Optional[TPM2_HANDLE]] = None template: ClassVar[TPM2B_PUBLIC] _templates: ClassVar[dict[str, type["ek_template"]]] = dict() _names: ClassVar[Sequence[str]] def __init_subclass__(cls): for name in cls._names: name = name.lower() ek_template._templates[name] = cls @classmethod def lookup(cls, name: str) -> "ek_template": name = name.lower() template = cls._templates.get(name, None) return template class ek_rsa2048(ek_template): _names = ("EK-RSA2048", "L-1") cert_index = TPM2_HANDLE(0x01C00002) nonce_index = cert_index + 1 template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=template_attributes.low, authPolicy=template_policy.low, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=template_symmetric.low, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=2048, ), ), unique=TPMU_PUBLIC_ID(rsa=b"\x00" * 256), ) ) class ek_ecc256(ek_template): _names = ("EK-ECC256", "L-2") cert_index = TPM2_HANDLE(0x01C0000A) nonce_index = cert_index + 1 template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=template_attributes.low, authPolicy=template_policy.low, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=template_symmetric.low, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ) ), unique=TPMU_PUBLIC_ID(ecc=TPMS_ECC_POINT(x=b"\x00" * 32, y=b"\x00" * 32)), ) ) class ek_high_rsa2048(ek_template): _names = ("EK-HIGH-RSA2048", "H-1") cert_index = TPM2_HANDLE(0x01C00012) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=template_attributes.high, authPolicy=template_policy.sha256, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=template_symmetric.low, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=2048, ), ), ) ) class ek_high_ecc256(ek_template): _names = ("EK-HIGH-ECC256", "H-2") cert_index = TPM2_HANDLE(0x01C00014) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=template_attributes.high, authPolicy=template_policy.sha256, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=template_symmetric.low, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) class ek_high_ecc384(ek_template): _names = ("EK-HIGH-ECC384", "H-3") cert_index = TPM2_HANDLE(0x01C00016) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA384, objectAttributes=template_attributes.high, authPolicy=template_policy.sha384, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=template_symmetric.aes256, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P384, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) class ek_high_ecc521(ek_template): _names = ("EK-HIGH-ECC521", "H-4") cert_index = TPM2_HANDLE(0x01C00018) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA512, objectAttributes=template_attributes.high, authPolicy=template_policy.sha512, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=template_symmetric.aes256, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P521, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) class ek_high_ecc_sm2_p256(ek_template): _names = ("EK-HIGH-ECCSM2P256", "H-5") cert_index = TPM2_HANDLE(0x01C0001A) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SM3_256, objectAttributes=template_attributes.high, authPolicy=template_policy.sm3_256, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=template_symmetric.sm4, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.SM2_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) class ek_high_rsa3072(ek_template): _names = ("EK-HIGH-RSA3072", "H-6") cert_index = TPM2_HANDLE(0x01C0001C) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA384, objectAttributes=template_attributes.high, authPolicy=template_policy.sha384, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=template_symmetric.aes256, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=3072, ), ), ) ) class ek_high_rsa4096(ek_template): _names = ("EK-HIGH-RSA4096", "H-7") cert_index = TPM2_HANDLE(0x01C0001E) template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA384, objectAttributes=template_attributes.high, authPolicy=template_policy.sha384, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=template_symmetric.aes256, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=4096, ), ), ) ) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/internal/utils.py000066400000000000000000000274761506405471500225260ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 import logging import sys from typing import List from .._libtpm2_pytss import ffi, lib from ..TSS2_Exception import TSS2_Exception try: from .versions import _versions except ImportError as e: # this is needed so docs can be generated without building if "sphinx" not in sys.modules: raise e else: _versions = dict() logger = logging.getLogger(__name__) # Peek into the loaded modules, if mock is loaded, set __MOCK__ to True, else False __MOCK__ = "sphinx" in sys.modules class TSS2Version: """Class for comparing git describe output Motivation: python's packaging version class follows pep-440, however that system was found incapable of reasoning about git describe output even when munging version strings into pep-440, I could not find a semantic that provided the correct ordering. This class takes a git describe string allows one to compare them to eachother like Pythons packaging.Version class. Args: version(str): git describe --always --dirty output. """ def __init__(self, version: str): self._version = version major = "0" minor = "0" patch = "0" rc = "0xFFFFFFFF" commits = "0" is_rc = "rc" in version is_dirty = "dirty" in version hunks = version.split(".") extra_data = version.split("-")[1:] def handle_extra(): nonlocal extra_data nonlocal commits nonlocal rc nonlocal version nonlocal is_rc # rc0-26-g1234-dirty if len(extra_data) == 4: if not is_rc: raise ValueError(f'Invalid version string, got: "{version}"') rc = extra_data[0][2:] commits = extra_data[1] # 26-g1234-dirty OR rc5-26-g1234 OR 1 elif len(extra_data) == 3: if is_rc: rc = extra_data[0][2:] commits = extra_data[1] elif is_dirty: commits = extra_data[0] else: raise ValueError(f'Invalid version string, got: "{version}"') # 26-g1234 OR rc0-dirty elif len(extra_data) == 2: if is_rc: rc = extra_data[0][2:] else: commits = extra_data[0] # rc0 OR dirty elif len(extra_data) == 1: if is_rc: rc = extra_data[0][2:] elif not is_dirty: commits = extra_data[0] elif len(extra_data) == 0: # No extra data to process, thats OK pass else: raise ValueError(f'Invalid version string, got: "{version}"') def cleanse(xstr): if "-" in xstr: return xstr[: xstr.find("-")] return xstr # 4, 4-76, 4-rc5, 4-rc5-26, 4-26-g1234-dirty, 4-rc0-26-g1234-dirty if len(hunks) == 1: major = cleanse(hunks[0]) minor = "0" patch = "0" handle_extra() # 4.0, 4.0-g1234-76, 4.0-rc5, 4.0-rc5-26-g1234, 4.0-26-g1234-dirty, 4.0-rc0-26-g1234-dirty elif len(hunks) == 2: major = hunks[0] minor = cleanse(hunks[1]) patch = "0" handle_extra() # 4.0, 4.0-76-g1234, 4.0-rc5, 4.0-rc5-26-g1234, 4.0-26-g1234-dirty, 4.0-rc0-26-g1234-dirty elif len(hunks) == 3: major = hunks[0] minor = hunks[1] patch = cleanse(hunks[2]) handle_extra() else: raise ValueError(f'Invalid version string, got: "{version}"') # Convert to int major = int(major, 0).to_bytes(4, byteorder="big") minor = int(minor, 0).to_bytes(4, byteorder="big") patch = int(patch, 0).to_bytes(4, byteorder="big") rc = int(rc, 0).to_bytes(4, byteorder="big") commits = int(commits, 0).to_bytes(4, byteorder="big") dirty = int(is_dirty).to_bytes(1, byteorder="big") # TO make reasoning easy we lay out a big int where each field # can hold 4 bytes of data, except for dirty which is a byte # MAJOR : MINOR : PATCH : RC : COMMITS : DIRTY concatenated = major + minor + patch + rc + commits + dirty v = int.from_bytes(concatenated, byteorder="big") self._value = v def __str__(self): return self._version def __lt__(self, other): x = other if isinstance(other, int) else other._value return self._value < x def __le__(self, other): x = other if isinstance(other, int) else other._value return self._value <= x def __eq__(self, other): x = other if isinstance(other, int) else other._value return self._value == x def __ne__(self, other): x = other if isinstance(other, int) else other._value return self._value != x def __ge__(self, other): x = other if isinstance(other, int) else other._value return self._value >= x def __gt__(self, other): x = other if isinstance(other, int) else other._value return self._value > x def _chkrc(rc, acceptable=None): if acceptable is None: acceptable = [] elif isinstance(acceptable, int): acceptable = [acceptable] acceptable += [lib.TPM2_RC_SUCCESS] if rc not in acceptable: raise TSS2_Exception(rc) def _to_bytes_or_null(value, allow_null=True, encoding=None): """Convert to cdata input. None: ffi.NULL (if allow_null == True) bytes: bytes str: str.encode() """ if encoding is None: encoding = "utf-8" if value is None: if allow_null: return ffi.NULL return b"" if isinstance(value, bytes): return value if isinstance(value, str): return value.encode(encoding=encoding) raise RuntimeError("Cannot convert value into bytes/null-pointer") #### Utilities #### def _CLASS_INT_ATTRS_from_string(cls, str_value, fixup_map=None): """ Given a class, lookup int attributes by name and return that attribute value. :param cls: The class to search. :param str_value: The key for the attribute in the class. """ friendly = { key.upper(): value for (key, value) in vars(cls).items() if isinstance(value, int) } if fixup_map is not None and str_value.upper() in fixup_map: str_value = fixup_map[str_value.upper()] return friendly[str_value.upper()] def _cpointer_to_ctype(x): tipe = ffi.typeof(x) if tipe.kind == "pointer": tipe = tipe.item return tipe def _fixup_cdata_kwargs(this, _cdata, kwargs): # folks may call this routine without a keyword argument which means it may # end up in _cdata, so we want to try and work this out unknown = None try: # is _cdata actual ffi data? ffi.typeof(_cdata) except (TypeError, ffi.error): # No, its some type of Python data # Is it the same instance and a coy constructor call? # ie TPMS_ECC_POINT(TPMS_ECC_POINT(x=... , y=...)) if isinstance(_cdata, type(this)): pyobj = _cdata _cdata = ffi.new(f"{this.__class__.__name__} *", pyobj._cdata[0]) else: # Its not a copy constructor, so it must be for a subfield, # so clear it from _cdata and call init unknown = _cdata _cdata = ffi.new(f"{this.__class__.__name__} *") # if it's unknown, find the field it's destined for. This is easy for TPML_ # and TPM2B_ types because their is only one field. if unknown is not None: tipe = _cpointer_to_ctype(_cdata) # ignore the field that is size or count, and get the one for the data size_field_name = "size" if "TPM2B_" in tipe.cname else "count" field_name = next((v[0] for v in tipe.fields if v[0] != size_field_name), None) if len(kwargs) != 0: raise RuntimeError( f"Ambiguous call, try using key {field_name} in parameters" ) if hasattr(unknown, "_cdata"): a = _cpointer_to_ctype(getattr(_cdata, field_name)) b = _cpointer_to_ctype(unknown._cdata) if a != b: expected = _fixup_classname(tipe) got = _fixup_classname(b) raise TypeError( f"Expected initialization from type {expected}, got {got}" ) kwargs[field_name] = unknown elif len(kwargs) == 0: return (_cdata, {}) return (_cdata, kwargs) def _ref_parent(data, parent): tipe = ffi.typeof(parent) if tipe.kind != "pointer": return data def deconstructor(ptr): parent return ffi.gc(data, deconstructor) def _convert_to_python_native(global_map, data, parent=None): if not isinstance(data, ffi.CData): return data if parent is not None: data = _ref_parent(data, parent) tipe = ffi.typeof(data) # Native arrays, like uint8_t[4] we don't wrap. We just let the underlying # data type handle it. if tipe.kind == "array" and tipe.cname.startswith("uint"): return data # if it's not a struct or union, we don't wrap it and thus we don't # know what to do with it. if tipe.kind != "struct" and tipe.kind != "union": raise TypeError(f'Not struct or union, got: "{tipe.kind}"') clsname = _fixup_classname(tipe) subclass = global_map[clsname] obj = subclass(_cdata=data) return obj def _fixup_classname(tipe): # Some versions of tpm2-tss had anonymous structs, so the kind will be struct # but the name will not contain it if tipe.cname.startswith(tipe.kind): return tipe.cname[len(tipe.kind) + 1 :] return tipe.cname def _mock_bail(): return __MOCK__ def _get_dptr(dptr, free_func): return ffi.gc(dptr[0], free_func) def _check_friendly_int(friendly, varname, clazz): if not isinstance(friendly, int): raise TypeError(f"expected {varname} to be type int, got {type(friendly)}") if not friendly in clazz: raise ValueError( f"expected {varname} value of {friendly} in class {str(clazz)}, however it's not found." ) def is_bug_fixed( fixed_in=None, backports: List[str] = None, lib: str = "tss2-fapi" ) -> bool: """Use pkg-config to determine if a bug was fixed in the currently installed tpm2-tss version.""" if fixed_in and _lib_version_atleast(lib, fixed_in): return True version = _versions.get(lib) if not version: return False version = version.split("-")[0] vers_major, vers_minor, vers_patch = (int(s) for s in version.split(".")) if backports is None: backports = [] for backport in backports: backp_major, backp_minor, backp_patch = (int(s) for s in backport.split(".")) if vers_major == backp_major and vers_minor == backp_minor: return vers_patch >= backp_patch return False def _check_bug_fixed( details, fixed_in=None, backports: List[str] = None, lib: str = "tss2-fapi", error: bool = False, ) -> None: """Emit a warning or exception if there is an unfixed bug in the currently installed tpm2-tss version.""" if not is_bug_fixed(fixed_in=fixed_in, backports=backports, lib=lib): version = _versions.get(lib) message = f"This API call {'is' if error else 'may be'} affected by a bug in {lib} version {version}: {details}\nPlease use >= {fixed_in}. Backports exist for {backports}." if error: raise RuntimeError(message) logger.warning(message) def _lib_version_atleast(tss2_lib, version): if tss2_lib not in _versions: return False libv = TSS2Version(_versions[tss2_lib]) lv = TSS2Version(version) return libv >= lv tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/policy.py000066400000000000000000000466171506405471500210470ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .internal.utils import _lib_version_atleast, _chkrc if not _lib_version_atleast("tss2-policy", "4.0.0"): raise NotImplementedError("tss2-policy not installed or version is less then 4.0.0") from .types import ( TPM2B_DIGEST, TPMS_NV_PUBLIC, TPM2B_NAME, TPMT_PUBLIC, TPM2B_NONCE, TSS2_OBJECT, TSS2_POLICY_PCR_SELECTION, TPM2_HANDLE, ) from .constants import TPM2_ALG, ESYS_TR, TSS2_RC, TPM2_RC from .TSS2_Exception import TSS2_Exception from ._libtpm2_pytss import ffi, lib from .ESAPI import ESAPI from enum import Enum from typing import Callable, Union class policy_cb_types(Enum): """Policy callback types""" CALC_PCR = 0 CALC_NAME = 1 CALC_PUBLIC = 2 CALC_NVPUBLIC = 3 EXEC_AUTH = 4 EXEC_POLSEL = 5 EXEC_SIGN = 6 EXEC_POLAUTH = 7 EXEC_POLAUTHNV = 8 EXEC_POLDUP = 9 EXEC_POLACTION = 10 @ffi.def_extern() def _policy_cb_calc_pcr(selection, out_selection, out_digest, userdata): """Callback wrapper for policy PCR calculations Args: selection (struct TSS2_POLICY_PCR_SELECTION): in out_selection (struct TPML_PCR_SELECTION): out out_digest (struct TPML_DIGEST): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.CALC_PCR) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: selcopy = ffi.new("TSS2_POLICY_PCR_SELECTION *", selection[0]) sel = TSS2_POLICY_PCR_SELECTION(_cdata=selcopy) cb_selection, cb_digest = cb(sel) out_selection.count = cb_selection.count for i in range(0, cb_selection.count): out_selection.pcrSelections[i] = cb_selection[i]._cdata out_digest.count = cb_digest.count for i in range(0, cb_digest.count): out_digest.digests[i].buffer = cb_digest[i] out_digest.digests[i].size = len(cb_digest[i]) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_calc_name(path, name, userdata): """Callback wrapper for policy name calculations Args: path (C string): in name (struct TPM2B_DIGEST): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.CALC_NAME) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: pth = ffi.string(path) cb_name = cb(pth) name.size = len(cb_name) name.name = bytes(cb_name.name) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_calc_public(path, public, userdata): """Callback wrapper for getting the public part for a key path Args: path (C string): in public (struct TPMT_PUBLIC): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.CALC_PUBLIC) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: pth = ffi.string(path) cb_public = cb(pth) public.type = cb_public.type public.nameAlg = cb_public.nameAlg public.objectAttributes = cb_public.objectAttributes public.authPolicy.buffer = bytes(cb_public.authPolicy) public.authPolicy.size = cb_public.authPolicy.size public.parameters = cb_public.parameters._cdata public.unique = cb_public.unique._cdata except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_calc_nvpublic(path, nv_index, nv_public, userdata): """Callback wrapper for getting the public part for a NV path Args: path (C string or NULL): in nv_index (TPMI_RH_NV_INDEX or zero): in nv_public (struct TPMS_NV_PUBLIC): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.CALC_NVPUBLIC) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: pth = ffi.string(path) if path != ffi.NULL else None index = TPM2_HANDLE(nv_index) cb_nv_public = cb(pth, index) nv_public.nvIndex = cb_nv_public.nvIndex nv_public.nameAlg = cb_nv_public.nameAlg nv_public.attributes = cb_nv_public.attributes nv_public.authPolicy.buffer = bytes(cb_nv_public.authPolicy) nv_public.authPolicy.size = cb_nv_public.authPolicy.size nv_public.dataSize = cb_nv_public.dataSize except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_auth(name, object_handle, auth_handle, auth_session, userdata): """Callback wrapper for getting authorization sessions for a name Args: name (struct TPM2B_NAME): in object_handle (ESYS_TR): out auth_handle (ESYS_TR): out auth_session (ESYS_TR): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_AUTH) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: nb = ffi.unpack(name.name, name.size) name2b = TPM2B_NAME(nb) cb_object_handle, cb_auth_handle, cb_auth_session = cb(name2b) object_handle[0] = cb_object_handle auth_handle[0] = cb_auth_handle auth_session[0] = cb_auth_session except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_polsel( auth_object, branch_names, branch_count, branch_idx, userdata ): """Callback wrapper selection of a policy branch Args: auth_object (struct TSS2_OBJECT): in branch_names (array of C strings): in branch_count (int): in branch_idx (int): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_POLSEL) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: obj = None if auth_object: obj = TSS2_OBJECT(handle=auth_object.handle) branches = list() for i in range(0, branch_count): branch = ffi.string(branch_names[i]) branches.append(branch) indx = cb(obj, branches) branch_idx[0] = indx except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_sign( key_pem, public_key_hint, key_pem_hash_alg, buf, buf_size, signature, signature_size, userdata, ): """Callback wrapper to signing an operation Args: key_pem (C string): in public_key_hint (C string): in key_pem_hash_alg (TPMI_ALG_HASH): in buf: (uint8_t array): in buf_size (size_t): in signature (pointer to uint8_t array): out signature_size (pointer to size_t): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_SIGN) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: pem = ffi.string(key_pem) key_hint = ffi.string(public_key_hint) hash_alg = TPM2_ALG(key_pem_hash_alg) b = bytes(ffi.unpack(buf, buf_size)) cb_signature = cb(pem, key_hint, hash_alg, b) signature[0] = ffi.new("char[]", cb_signature) signature_size[0] = len(cb_signature) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_polauth( key_public, hash_alg, digest, policy_ref, signature, userdata ): """Callback for signing a policy Args: key_public (struct TPMT_PUBLIC): in hash_alg (TPM2_ALG_ID): in digest (struct TPM2B_DIGEST): in policy_ref (struct TPM2B_NONCE): in signature (struct TPMT_SIGNATURE): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_POLAUTH) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: key_pub = TPMT_PUBLIC(_cdata=key_public) halg = TPM2_ALG(hash_alg) db = ffi.unpack(digest.buffer, digest.size) pb = ffi.unpack(policy_ref.buffer, policy_ref.size) dig = TPM2B_DIGEST(db) polref = TPM2B_NONCE(pb) cb_signature = cb(key_pub, halg, dig, polref) signature.sigAlg = cb_signature.sigAlg signature.signature = cb_signature.signature._cdata except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_polauthnv(nv_public, hash_alg, userdata): """Callback wrapper for NV policy authorization Args: nv_public (struct TPMS_NV_PUBLIC): in hash_alg (TPM2_ALG_ID): in userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_POLAUTHNV) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: nvp = TPMS_NV_PUBLIC(nv_public) halg = TPM2_ALG(hash_alg) cb(nvp, halg) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_poldup(name, userdata): """Callback wrapper to get name for duplication selection Args: name (struct TPM2B_NAME): out userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_POLDUP) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: cb_name = cb() name.size = len(cb_name) name.name = bytes(cb_name) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS @ffi.def_extern() def _policy_cb_exec_polaction(action, userdata): """Callback wrapper for policy action Args: action (C string): in userdata (ffi handle): in """ pi = ffi.from_handle(userdata) cb = pi._get_callback(policy_cb_types.EXEC_POLACTION) if not cb: return TSS2_RC.POLICY_RC_NULL_CALLBACK try: ab = ffi.string(action) cb(ab) except Exception as e: rc = ( e.rc if isinstance(e, TSS2_Exception) else TSS2_RC.POLICY_RC_GENERAL_FAILURE ) pi._callback_exception = e return rc return TPM2_RC.SUCCESS class policy(object): """Initialize policy object. Args: policy (Union(bytes, str]): The JSON policy to calculate or execute. hash_alg (TPM2_ALG): The hash algorithm to use for policy calculations. Returns: An instance of the policy object. This class implements the policy part of the TCG TSS 2.0 JSON Data Types and Policy Language Specification. The specification can be found at https://trustedcomputinggroup.org/resource/tcg-tss-json/ """ def __init__(self, policy: Union[bytes, str], hash_alg: TPM2_ALG): if isinstance(policy, str): policy = policy.encode() self._policy = policy self._hash_alg = hash_alg self._callbacks = dict() self._callback_exception = None self._ctx_pp = ffi.new("TSS2_POLICY_CTX **") _chkrc(lib.Tss2_PolicyInit(policy, hash_alg, self._ctx_pp)) self._ctx = self._ctx_pp[0] self._handle = ffi.new_handle(self) self._calc_callbacks = ffi.new("TSS2_POLICY_CALC_CALLBACKS *") self._exec_callbacks = ffi.new("TSS2_POLICY_EXEC_CALLBACKS *") def __enter__(self): return self def __exit__(self, _type, value, traceback): self.close() def close(self): """Finalize the policy instance""" lib.Tss2_PolicyFinalize(self._ctx_pp) self._ctx_pp = ffi.NULL self._ctx = ffi.NULL @property def policy(self) -> bytes: """bytes: The JSON policy.""" return self._policy @property def hash_alg(self) -> TPM2_ALG: """TPM2_ALG: The hash algorithm to be used during policy calculcation.""" return self._hash_alg def _get_callback(self, callback_type: policy_cb_types) -> Callable: return self._callbacks.get(callback_type) def set_callback( self, callback_type: policy_cb_types, callback: Union[None, Callable] ): """Set callback for policy calculaction or execution Args: callback_type (policy_cb_types): Which callback to set or unset. callback (Union[None, Callable]): The callback function to call, or None to remove the callback. Raises: ValueError """ userdata = self._handle if callback is None: userdata = ffi.NULL update_calc = False update_exec = False if callback_type == policy_cb_types.CALC_PCR: self._callbacks[callback_type] = callback self._calc_callbacks.cbpcr = lib._policy_cb_calc_pcr self._calc_callbacks.cbpcr_userdata = userdata update_calc = True elif callback_type == policy_cb_types.CALC_NAME: self._callbacks[callback_type] = callback self._calc_callbacks.cbname = lib._policy_cb_calc_name self._calc_callbacks.cbname_userdata = userdata update_calc = True elif callback_type == policy_cb_types.CALC_PUBLIC: self._callbacks[callback_type] = callback self._calc_callbacks.cbpublic = lib._policy_cb_calc_public self._calc_callbacks.cbpublic_userdata = userdata update_calc = True elif callback_type == policy_cb_types.CALC_NVPUBLIC: self._callbacks[callback_type] = callback self._calc_callbacks.cbnvpublic = lib._policy_cb_calc_nvpublic self._calc_callbacks.cbnvpublic_userdata = userdata update_calc = True elif callback_type == policy_cb_types.EXEC_AUTH: self._callbacks[callback_type] = callback self._exec_callbacks.cbauth = lib._policy_cb_exec_auth self._exec_callbacks.cbauth_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_POLSEL: self._callbacks[callback_type] = callback self._exec_callbacks.cbpolsel = lib._policy_cb_exec_polsel self._exec_callbacks.cbpolsel_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_SIGN: self._callbacks[callback_type] = callback self._exec_callbacks.cbsign = lib._policy_cb_exec_sign self._exec_callbacks.cbsign_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_POLAUTH: self._callbacks[callback_type] = callback self._exec_callbacks.cbauthpol = lib._policy_cb_exec_polauth self._exec_callbacks.cbauthpol_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_POLAUTHNV: self._callbacks[callback_type] = callback self._exec_callbacks.cbauthnv = lib._policy_cb_exec_polauthnv self._exec_callbacks.cbauthnv_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_POLDUP: self._callbacks[callback_type] = callback self._exec_callbacks.cbdup = lib._policy_cb_exec_poldup self._exec_callbacks.cbdup_userdata = userdata update_exec = True elif callback_type == policy_cb_types.EXEC_POLACTION: self._callbacks[callback_type] = callback self._exec_callbacks.cbaction = lib._policy_cb_exec_polaction self._exec_callbacks.cbaction_userdata = userdata update_exec = True else: raise ValueError(f"unsupported callback type {callback_type}") if update_calc: _chkrc(lib.Tss2_PolicySetCalcCallbacks(self._ctx, self._calc_callbacks)) elif update_exec: _chkrc(lib.Tss2_PolicySetExecCallbacks(self._ctx, self._exec_callbacks)) def execute(self, esys_ctx: ESAPI, session: ESYS_TR): """Executes the policy Args: esys_ctx (ESAPI): The ESAPI instance to use during policy execution. session (ESYS_TR): The policy session to use during execution. Raises: TSS2_Exception or any possible exception from a callback function. """ try: _chkrc(lib.Tss2_PolicyExecute(self._ctx, esys_ctx._ctx, session)) except Exception as e: if self._callback_exception is not None: raise self._callback_exception raise e finally: self._callback_exception = None def calculate(self): """Calculate the policy Raises: TSS2_Exception """ try: _chkrc(lib.Tss2_PolicyCalculate(self._ctx)) except Exception as e: if self._callback_exception is not None: raise self._callback_exception raise e finally: self._callback_exception = None def get_calculated_json(self) -> bytes: """Get the calculated policy as JSON Returns: The calculated JSON policy as bytes Raises: TSS2_Exception """ size = ffi.new("size_t *") _chkrc(lib.Tss2_PolicyGetCalculatedJSON(self._ctx, ffi.NULL, size)) cjson = ffi.new("uint8_t[]", size[0]) _chkrc(lib.Tss2_PolicyGetCalculatedJSON(self._ctx, cjson, size)) return ffi.string(cjson, size[0]) @property def description(self) -> bytes: """bytes: The policy description.""" size = ffi.new("size_t *") _chkrc(lib.Tss2_PolicyGetDescription(self._ctx, ffi.NULL, size)) desc = ffi.new("uint8_t[]", size[0]) _chkrc(lib.Tss2_PolicyGetDescription(self._ctx, desc, size)) return ffi.string(desc, size[0]) def get_calculated_digest(self) -> TPM2B_DIGEST: """Get the digest of the calculated policy Returns: The digest as a TPM2B_DIGEST. Raises: TSS2_Exception """ dig = ffi.new("TPM2B_DIGEST *") _chkrc(lib.Tss2_PolicyGetCalculatedDigest(self._ctx, dig)) return TPM2B_DIGEST(_cdata=dig[0]) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/tsskey.py000066400000000000000000000265601506405471500210650ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 import warnings from ._libtpm2_pytss import lib from .types import * from .constants import TPM2_ECC, TPM2_CAP, ESYS_TR from asn1crypto.core import ObjectIdentifier, Sequence, Boolean, OctetString, Integer from asn1crypto import pem _parent_rsa_template = TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, authPolicy=b"", parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=2048, exponent=0, ), ), ) _parent_ecc_template = TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, authPolicy=b"", parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ) _rsa_template = TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, authPolicy=b"", parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.NULL), scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), ), ), ) _ecc_template = TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, authPolicy=b"", parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.NULL), scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ) _loadablekey_oid = ObjectIdentifier("2.23.133.10.1.3") # _BooleanOne is used to encode True in the same way as tpm2-tss-engine class _BooleanOne(Boolean): def set(self, value): self._native = bool(value) self.contents = b"\x00" if not value else b"\x01" self._header = None if self._trailer != b"": self._trailer = b"" class TSSPrivKey(object): """TSSPrivKey is class to create/load keys for/from tpm2-tss-engine / tpm2-openssl. Note: Most users should use create_rsa/create_ecc together with to_pem and from_pem together with load. """ class _tssprivkey_der(Sequence): _fields = [ ("type", ObjectIdentifier), ("empty_auth", _BooleanOne, {"explicit": 0, "optional": True}), ("parent", Integer), ("public", OctetString), ("private", OctetString), ] def __init__(self, private, public, empty_auth=True, parent=lib.TPM2_RH_OWNER): """Initialize TSSPrivKey using raw values. Args: private (TPM2B_PRIVATE): The private part of the TPM key. public (TPM2B_PUBLIC): The public part of the TPM key. empty_auth (bool): Defines if the authorization is a empty password, default is True. parent (int): The parent of the key, either a persistent key handle or TPM2_RH_OWNER, default is TPM2_RH_OWNER. """ self._private = private self._public = public self._empty_auth = bool(empty_auth) self._parent = parent @property def private(self): """TPM2B_PRIVATE: The private part of the TPM key.""" return self._private @property def public(self): """TPM2B_PUBLIC: The public part of the TPM key.""" return self._public @property def empty_auth(self): """bool: Defines if the authorization is a empty password.""" return self._empty_auth @property def parent(self): """int: Handle of the parent key.""" return self._parent def to_der(self): """Encode the TSSPrivKey as DER encoded ASN.1. Returns: Returns the DER encoding as bytes. """ seq = self._tssprivkey_der() seq["type"] = _loadablekey_oid.native seq["empty_auth"] = self.empty_auth seq["parent"] = self.parent pub = self.public.marshal() seq["public"] = pub priv = self.private.marshal() seq["private"] = priv return seq.dump() def to_pem(self): """Encode the TSSPrivKey as PEM encoded ASN.1. Returns: Returns the PEM encoding as bytes. """ der = self.to_der() return pem.armor("TSS2 PRIVATE KEY", der) @staticmethod def _getparenttemplate(ectx): more = True al = list() while more: more, data = ectx.get_capability(TPM2_CAP.ALGS, 0, lib.TPM2_MAX_CAP_ALGS) algs = data.data.algorithms for i in range(0, algs.count): al.append(algs.algProperties[i].alg) if TPM2_ALG.ECC in al: return _parent_ecc_template elif TPM2_ALG.RSA in al: return _parent_rsa_template return None @staticmethod def _getparent(ectx, keytype, parent): if parent == lib.TPM2_RH_OWNER: template = TSSPrivKey._getparenttemplate(ectx) else: return ectx.tr_from_tpmpublic(parent) if template is None: raise RuntimeError("Unable to find supported parent key type") inpub = TPM2B_PUBLIC(publicArea=template) phandle, _, _, _, _ = ectx.create_primary( primary_handle=ESYS_TR.RH_OWNER, in_sensitive=TPM2B_SENSITIVE_CREATE(), in_public=inpub, outside_info=TPM2B_DATA(), creation_pcr=TPML_PCR_SELECTION(), session1=ESYS_TR.PASSWORD, ) return phandle def load(self, ectx, password=None): """Load the TSSPrivKey. Args: ectx (ESAPI): The ESAPI instance to use for loading the key. password (bytes): The password of the TPM key, default is None. Returns: An ESYS_TR handle. """ if not password and not self.empty_auth: raise RuntimeError("no password specified but it is required") elif password and self.empty_auth: warnings.warn("password specified but empty_auth is true") phandle = self._getparent(ectx, self.public.publicArea.type, self.parent) with phandle as phandle: handle = ectx.load(phandle, self.private, self.public) ectx.tr_set_auth(handle, password) return handle @classmethod def create(cls, ectx, template, parent=lib.TPM2_RH_OWNER, password=None): """Create a TssPrivKey using a template. Note: Most users should use the create_rsa or create_ecc methods. Args: ectx (ESAPI): The ESAPI instance to use for creating the key. template (TPM2B_PUBLIC): The key template. parent (int): The parent of the key, default is TPM2_RH_OWNER. password (bytes): The password to set for the key, default is None. Returns: Returns a TSSPrivKey instance with the created key. """ insens = TPM2B_SENSITIVE_CREATE() emptyauth = True if password: insens.sensitive.userAuth = password emptyauth = False phandle = cls._getparent(ectx, template.type, parent) with phandle as phandle: private, public, _, _, _ = ectx.create( parent_handle=phandle, in_sensitive=insens, in_public=TPM2B_PUBLIC(publicArea=template), outside_info=TPM2B_DATA(), creation_pcr=TPML_PCR_SELECTION(), ) return cls(private, public, emptyauth, parent) @classmethod def create_rsa( cls, ectx, keyBits=2048, exponent=0, parent=lib.TPM2_RH_OWNER, password=None ): """Create a RSA TssPrivKey using a standard RSA key template. Args: ectx (ESAPI): The ESAPI instance to use for creating the key. keyBits (int): Size of the RSA key, default is 2048. exponent (int): The exponent to use for the RSA key, default is 0 (TPM default). parent (int): The parent of the key, default is TPM2_RH_OWNER. password (bytes): The password to set for the key, default is None. Returns: Returns a TSSPrivKey instance with the created RSA key. """ template = _rsa_template template.parameters.rsaDetail.keyBits = keyBits template.parameters.rsaDetail.exponent = exponent return cls.create(ectx, template, parent, password) @classmethod def create_ecc( cls, ectx, curveID=TPM2_ECC.NIST_P256, parent=lib.TPM2_RH_OWNER, password=None ): """Create an ECC TssPrivKey using a standard ECC key template. Args: ectx (ESAPI): The ESAPI instance to use for creating the key. curveID (int): The ECC curve to be used, default is TPM2_ECC.NIST_P256. parent (int): The parent of the key, default is TPM2_RH_OWNER. password (bytes): The password to set for the key, default is None. Returns: Returns a TSSPrivKey instance with the created ECC key. """ template = _ecc_template template.parameters.eccDetail.curveID = curveID return cls.create(ectx, template, parent, password) @classmethod def from_der(cls, data): """Load a TSSPrivKey from DER ASN.1. Args: data (bytes): The DER encoded ASN.1. Returns: Returns a TSSPrivKey instance. """ seq = cls._tssprivkey_der.load(data) if seq["type"].native != _loadablekey_oid.native: raise TypeError("unsupported key type") empty_auth = seq["empty_auth"].native parent = seq["parent"].native public, _ = TPM2B_PUBLIC.unmarshal(bytes(seq["public"])) private, _ = TPM2B_PRIVATE.unmarshal(bytes(seq["private"])) return cls(private, public, empty_auth, parent) @classmethod def from_pem(cls, data): """Load a TSSPrivKey from PEM ASN.1. Args: data (bytes): The PEM encoded ASN.1. Returns: Returns a TSSPrivKey instance. """ pem_type, _, der = pem.unarmor(data) if pem_type != "TSS2 PRIVATE KEY": raise TypeError("unsupported PEM type") return cls.from_der(der) tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/types.py000066400000000000000000002221701506405471500207020ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 """ The types module contains types for each of the corresponding TPM types from the following TCG specifications: - https://trustedcomputinggroup.org/resource/tpm-library-specification/. See Part 2 "Structures". - https://trustedcomputinggroup.org/resource/tss-overview-common-structures-specification The classes contained within can be initialized based on named argument value pairs or dictionaries of key-value objects where the keys are the names of the associated type. """ from ._libtpm2_pytss import ffi, lib from tpm2_pytss.internal.utils import ( _chkrc, _fixup_cdata_kwargs, _cpointer_to_ctype, _fixup_classname, _convert_to_python_native, _mock_bail, _ref_parent, _lib_version_atleast, ) from tpm2_pytss.internal.crypto import ( _calculate_sym_unique, _get_digest_size, _public_from_encoding, _private_from_encoding, _public_to_pem, _getname, _verify_signature, _get_signature_bytes, private_to_key, ) import tpm2_pytss.constants as constants # lgtm [py/import-and-import-from] from tpm2_pytss.constants import ( TPMA_OBJECT, TPM2_ALG, TPM2_ECC_CURVE, TPM2_SE, TPM2_HR, TPM_INT_MU, ) from typing import Union, Tuple, Optional import sys try: from tpm2_pytss.internal.type_mapping import _type_map, _element_type_map except ImportError as e: # this is needed so docs can be generated without building if "sphinx" not in sys.modules: raise e import binascii import secrets from cryptography.hazmat.primitives import serialization class ParserAttributeError(Exception): """Exception ocurred when when parsing.""" pass class TPM2_HANDLE(int, TPM_INT_MU): """A handle to a TPM address""" class TPM_BASE_OBJECT(object): """Abstract Base class for all TPM Objects. Not suitable for direct instantiation.""" def __init__(self, _cdata=None, **kwargs): # Rather than trying to mock the FFI interface, just avoid it and return # the base object. This is really only needed for documentation, and it # makes it work. Why Yes, this is a terrible hack (cough cough). if _mock_bail(): return _cdata, kwargs = _fixup_cdata_kwargs(self, _cdata, kwargs) object.__setattr__(self, "_cdata", _cdata) tipe = _cpointer_to_ctype(self._cdata) expected_cname = _fixup_classname(tipe) # Because we alias TPM2B_AUTH as a TPM2B_DIGEST in the C code if ( expected_cname != "TPM2B_DIGEST" and expected_cname != self.__class__.__name__ and "TPM2B_" not in expected_cname ): raise TypeError( f"Unexpected _cdata type {expected_cname}, expected {self.__class__.__name__}" ) fields = {x[0]: x[1].type for x in tipe.fields} for k, v in kwargs.items(): if k not in fields: raise AttributeError( f"{self.__class__.__name__} has no field by the name of {k}" ) cname = fields[k] if cname.kind not in ("primitive", "array", "enum"): clsname = _fixup_classname(cname) clazz = globals()[clsname] # If subclass object is a TPM2B SIMPLE object, and we have a raw str, or bytes, convert if issubclass(clazz, TPM2B_SIMPLE_OBJECT) and isinstance( v, (str, bytes) ): _bytefield = clazz._get_bytefield() subobj = clazz(_cdata=None) setattr(subobj, _bytefield, v) v = subobj TPM_BASE_OBJECT.__setattr__(self, k, v) def __getattribute__(self, key): try: # go through object to avoid invoking THIS objects __getattribute__ call # and thus infinite recursion return object.__getattribute__(self, key) except AttributeError: # Ok the object has no idea what you're looking for... can we handle it? # Yes we could use self._cdata as it will only recurse once, but lets avoid it. _cdata = object.__getattribute__(self, "_cdata") # Get the attribute they're looking for out of _cdata x = getattr(_cdata, key) tm = _type_map.get((self.__class__.__name__, key)) if tm is not None and hasattr(constants, tm): c = getattr(constants, tm) obj = c(x) elif tm is not None: obj = globals()[tm](x) else: obj = _convert_to_python_native(globals(), x, parent=self._cdata) return obj def __setattr__(self, key, value): _value = value _cdata = object.__getattribute__(self, "_cdata") if isinstance(value, TPM_BASE_OBJECT): tipe = ffi.typeof(value._cdata) if tipe.kind in ["struct", "union"]: value = value._cdata else: value = value._cdata[0] try: # Get _cdata without invoking getattr setattr(_cdata, key, value) except AttributeError: object.__setattr__(self, key, value) except TypeError as e: data = getattr(_cdata, key) tipe = ffi.typeof(data) clsname = _fixup_classname(tipe) clazz = None try: clazz = globals()[clsname] except KeyError: raise e fn = getattr(clazz, "_get_bytefield", None) if fn is None: src = ffi.addressof(value) x = getattr(_cdata, key) dest = ffi.addressof(x) a = ffi.typeof(src) b = ffi.typeof(dest) self_cls = type(getattr(self, key)) value_cls = type(_value) if ( a.cname != b.cname and not issubclass(self_cls, value_cls) or ffi.sizeof(value) != ffi.sizeof(x) ): raise TypeError( f"Cannot assign type {value_cls} to type {self_cls}" ) ffi.memmove(dest, src, ffi.sizeof(value)) return _bytefield = fn() data = getattr(data, _bytefield) tipe = ffi.typeof(data) if tipe.kind != "array" or not issubclass(clazz, TPM2B_SIMPLE_OBJECT): raise e if isinstance(value, str): value = value.encode() subobj = clazz(_cdata=None) setattr(subobj, _bytefield, value) value = subobj # recurse so we can get handling of setattr with Python wrapped data setattr(self, key, value) def __dir__(self): return object.__dir__(self) + dir(self._cdata) class TPM_OBJECT(TPM_BASE_OBJECT): """Base class struct types, not suitable for direct instantiation.""" def marshal(self): """Marshal instance into bytes. Returns: Returns the marshaled type as bytes. """ mfunc = getattr(lib, f"Tss2_MU_{self.__class__.__name__}_Marshal", None) if mfunc is None: raise RuntimeError( f"No marshal function found for {self.__class__.__name__}" ) _cdata = self._cdata tipe = ffi.typeof(_cdata) if tipe.kind != "pointer": _cdata = ffi.new(f"{self.__class__.__name__} *", self._cdata) offset = ffi.new("size_t *") buf = ffi.new("uint8_t[4096]") _chkrc(mfunc(_cdata, buf, 4096, offset)) return bytes(buf[0 : offset[0]]) @classmethod def unmarshal(cls, buf): """Unmarshal bytes into type instance. Args: buf (bytes): The bytes to be unmarshaled. Returns: Returns an instance of the current type and the number of bytes consumed. """ umfunc = getattr(lib, f"Tss2_MU_{cls.__name__}_Unmarshal", None) if umfunc is None: raise RuntimeError(f"No unmarshal function found for {cls.__name__}") if isinstance(buf, TPM2B_SIMPLE_OBJECT): buf = bytes(buf) _cdata = ffi.new(f"{cls.__name__} *") offset = ffi.new("size_t *") _chkrc(umfunc(buf, len(buf), offset, _cdata)) return cls(_cdata=_cdata), offset[0] def __eq__(self, other: "TPM_OBJECT") -> bool: if not isinstance(other, self.__class__): return False self_bytes = self.marshal() other_bytes = other.marshal() return self_bytes == other_bytes class TPM2B_SIMPLE_OBJECT(TPM_OBJECT): """Abstract Base class for all TPM2B Simple Objects. A Simple object contains only a size and byte buffer fields. This is not suitable for direct instantiation.""" def __init__(self, _cdata=None, **kwargs): _cdata, kwargs = _fixup_cdata_kwargs(self, _cdata, kwargs) _bytefield = type(self)._get_bytefield() for k, v in kwargs.items(): if k == "size": raise AttributeError(f"{k} is read only") if k != _bytefield: raise AttributeError(f"{self.__name__} has no field {k}") if isinstance(v, str): v = v.encode() setattr(_cdata, k, v) _cdata.size = len(v) super().__init__(_cdata=_cdata) @classmethod def _get_bytefield(cls): tipe = ffi.typeof(f"{cls.__name__}") for f in tipe.fields: if f[0] != "size": return f[0] return None def __setattr__(self, key, value): if key == "size": raise AttributeError(f"{key} is read only") _bytefield = type(self)._get_bytefield() if key == _bytefield: if isinstance(value, str): value = value.encode() setattr(self._cdata, key, value) self._cdata.size = len(value) else: super().__setattr__(key, value) def __getattribute__(self, key): _bytefield = type(self)._get_bytefield() if key == _bytefield: b = getattr(self._cdata, _bytefield) rb = _ref_parent(b, self._cdata) return memoryview(ffi.buffer(rb, self._cdata.size)) return super().__getattribute__(key) def __len__(self): return self._cdata.size def __getitem__(self, index): _bytefield = type(self)._get_bytefield() buf = getattr(self, _bytefield) if isinstance(index, int): if index >= self._cdata.size: raise IndexError("out of range") return buf[index] elif isinstance(index, slice): return buf[index] else: raise TypeError("index must an int or a slice") def __bytes__(self): _bytefield = type(self)._get_bytefield() buf = getattr(self, _bytefield) return bytes(buf) def __str__(self) -> str: """Returns a hex string representation of the underlying buffer. This is the same as: .. code-block:: python bytes(tpm2b_type).hex() Returns (str): A hex encoded string of the buffer. """ b = self.__bytes__() return binascii.hexlify(b).decode() def __eq__(self, value): b = self.__bytes__() return b == value class TPML_Iterator(object): """Iterator class for iterating over TPML data types. This class is used in enumerated for loops, such as: .. code-block:: python for alg in TPML_ALG: do_something(alg) """ def __init__(self, tpml): self._tpml = tpml self._index = 0 def __iter__(self): return self def __next__(self): if self._index > self._tpml.count - 1: raise StopIteration x = self._tpml[self._index] self._index = self._index + 1 return x class TPML_OBJECT(TPM_OBJECT): """Abstract Base class for all TPML Objects. A TPML object is an object that contains a list of objects. This is not suitable for direct instantiation.""" def __init__(self, _cdata=None, **kwargs): _cdata, kwargs = _fixup_cdata_kwargs(self, _cdata, kwargs) super().__init__(_cdata=_cdata) # Nothing todo if len(kwargs) == 0: return key = [*kwargs][0] cdata_array = self._cdata.__getattribute__(key) if isinstance(kwargs[key], TPM_OBJECT): kwargs[key] = [kwargs[key]] if not isinstance(kwargs[key], (list, tuple)): raise TypeError( "Expected initializer for TPML data types to be a list or tuple" ) expected_class = TPM_OBJECT try: tipe = ffi.typeof(cdata_array[0]) clsname = _fixup_classname(tipe) expected_class = globals()[clsname] except TypeError: # Was a native type, just use it pass for i, x in enumerate(kwargs[key]): if not isinstance(x, (expected_class, int)): try: x = expected_class(x) except TypeError: # Provide a better error message raise TypeError( f'Expected item at index {i} to be a TPM_OBJECT, got: "{type(x)}"' ) cdata_array[i] = x._cdata[0] if isinstance(x, TPM_OBJECT) else x self._cdata.count = len(kwargs[key]) def __getattribute__(self, key): try: # Can the parent handle it? x = TPM_OBJECT.__getattribute__(self, key) return x except TypeError: pass # Must be a TPML style array # Get cdata without implicitly invoking a derived classes __getattribute__ # This will prevent recursion and stack depth issues. _cdata = object.__getattribute__(self, "_cdata") # This will invoke the CFFI implementation, so getattr is safe here. x = getattr(_cdata, key) # If this isn't a CFFI type, something wen't crazy, and typeof() will raise TypeError. tipe = ffi.typeof(x) if tipe.kind != "array": raise TypeError( f'Unknown scalar conversion for kind "{tipe.kind}" for key "{key}"' ) # subclasses in the arrays within the CTypes are fixed, so # we only need to do this once clsname = _fixup_classname(tipe.item) subclass = globals()[clsname] l = [] # do not go through __len__ count = _cdata.count for i in range(0, count): obj = subclass(_cdata=x[i]) l.append(obj) return l def __getitem__(self, item): item_was_int = isinstance(item, int) try: return object.__getitem__(self, item) except AttributeError: pass if not isinstance(item, (int, slice)): raise TypeError( f"list indices must be integers or slices, not {type(item)}" ) # figure out what part named _cdata to go into tipe = ffi.typeof(self._cdata) if tipe.kind == "pointer": tipe = tipe.item field_name = next((v[0] for v in tipe.fields if v[0] != "count"), None) if isinstance(item, int): item = slice(item, item + 1) if item.stop is None: item = slice(item.start, len(self) - 1, item.step) # get the cdata field cdata_list = self._cdata.__getattribute__(field_name) cdatas = cdata_list[item] tm = _element_type_map.get(self.__class__.__name__) if tm is not None and hasattr(constants, tm): c = getattr(constants, tm) cdatas = [c(x) for x in cdatas] elif tm is not None: cdatas = [globals()[tm](x) for x in cdatas] if len(cdatas) > 0 and not isinstance(cdatas[0], ffi.CData): return cdatas[0] if item_was_int else cdatas # convert it to python native objects = [_convert_to_python_native(globals(), x, self._cdata) for x in cdatas] if isinstance(objects[0], TPM2B_SIMPLE_OBJECT): objects = [bytes(x) for x in objects] return objects[0] if item_was_int else objects def __len__(self): return self._cdata.count def __setitem__(self, key, value): if not isinstance(key, (int, slice)): raise TypeError(f"list indices must be integers or slices, not {type(key)}") if isinstance(key, int) and not isinstance(value, (TPM_OBJECT, int)): raise TypeError( f"expected value to be TPM_OBJECT or integer not {type(value)}" ) tipe = ffi.typeof(self._cdata) if tipe.kind == "pointer": tipe = tipe.item field_name = next((v[0] for v in tipe.fields if v[0] != "count"), None) cdata_list = self._cdata.__getattribute__(field_name) # make everything looks like slice if isinstance(key, int): key = slice(key, key + 1, 1) value = [value] elif key.step is None: key = slice(key.start, key.stop, 1) r = range(key.start, key.stop, key.step) if len(r) != len(value): raise ValueError("Expected {len(r)} items to unpack, got: {len(value)}") for value_offset, cdata_offset in enumerate(r): x = value[value_offset] x = x._cdata[0] if isinstance(x, TPM_OBJECT) else x cdata_list[cdata_offset] = x if key.stop > self._cdata.count: self._cdata.count = key.stop def __iter__(self): return TPML_Iterator(self) class TPMU_OBJECT(TPM_BASE_OBJECT): """Base class for union types, not suitable for direct instantiation.""" def marshal(self, selector: int) -> bytes: """Marshal union instance into bytes. Args: selector (int): The union selector. Returns: Returns the marshaled type as bytes. """ mfunc = getattr(lib, f"Tss2_MU_{self.__class__.__name__}_Marshal", None) if mfunc is None: raise RuntimeError( f"No marshal function found for {self.__class__.__name__}" ) _cdata = self._cdata tipe = ffi.typeof(_cdata) if tipe.kind != "pointer": _cdata = ffi.new(f"{self.__class__.__name__} *", self._cdata) offset = ffi.new("size_t *") buf = ffi.new("uint8_t[4096]") _chkrc(mfunc(_cdata, selector, buf, 4096, offset)) return bytes(buf[0 : offset[0]]) @classmethod def unmarshal(cls, selector: int, buf: bytes): """Unmarshal bytes into type instance. Args: selector (int): The union selector. buf (bytes): The bytes to be unmarshaled. Returns: Returns an instance of the current type and the number of bytes consumed. """ umfunc = getattr(lib, f"Tss2_MU_{cls.__name__}_Unmarshal", None) if umfunc is None: raise RuntimeError(f"No unmarshal function found for {cls.__name__}") if isinstance(buf, TPM2B_SIMPLE_OBJECT): buf = bytes(buf) _cdata = ffi.new(f"{cls.__name__} *") offset = ffi.new("size_t *") _chkrc(umfunc(buf, len(buf), offset, selector, _cdata)) return cls(_cdata=_cdata), offset[0] class TPMU_PUBLIC_PARMS(TPMU_OBJECT): pass class TPMT_PUBLIC_PARMS(TPM_OBJECT): pass class TPMT_ASYM_SCHEME(TPM_OBJECT): pass class TPM2B_NAME(TPM2B_SIMPLE_OBJECT): pass def _handle_sym_common(objstr, default_mode="null"): if objstr is None or len(objstr) == 0: objstr = "128" bits = objstr[:3] expected = ["128", "192", "256"] if bits not in expected: raise ValueError(f'Expected bits to be one of {expected}, got: "{bits}"') bits = int(bits) # go past bits objstr = objstr[3:] if len(objstr) == 0: mode = default_mode else: expected = ["cfb", "cbc", "ofb", "ctr", "ecb"] if objstr not in expected: raise ValueError(f'Expected mode to be one of {expected}, got: "{objstr}"') mode = objstr mode = TPM2_ALG.parse(mode) return (bits, mode) class TPMT_SYM_DEF(TPM_OBJECT): @classmethod def parse( cls, alg: str, is_restricted: bool = False, is_rsapss: bool = False ) -> "TPMT_SYM_DEF": """Builds a TPMT_SYM_DEF from a tpm2-tools like specifier strings. TPMT_SYM_DEF can be built from the symmetric algorithm string specifiers that the tpm2-tools project uses, for example, strings like "aes128cbc". Args: alg (str): The string specifier for the algorithm type, bitsize, and mode. Note strings "aes" and "aes128" are shorthand for "aes128cfb". Returns: A populated TPMT_SYM_DEF for use. Raises: ValueError: If a string value is not of an expected format. Examples: .. code-block:: python TPMT_SYM_DEF.parse("aes256cfb") TPMT_SYM_DEF.parse("aes") TPMT_SYM_DEF.parse("aes128cbc") """ t = cls() if alg is None or alg == "": alg = "aes128cfb" if is_restricted or is_rsapss else "null" if alg == "null": t.algorithm = TPM2_ALG.NULL return t if alg.startswith("aes"): t.algorithm = TPM2_ALG.AES alg = alg[3:] elif alg.startswith("camellia"): t.algorithm = TPM2_ALG.CAMELLIA alg = alg[8:] elif alg.startswith("sm4"): t.algorithm = TPM2_ALG.SM4 alg = alg[3:] elif alg == "xor": t.algorithm = TPM2_ALG.XOR return t else: raise ValueError( f'Expected symmetric alg to be null, xor or start with one of aes, camellia, sm4, got: "{alg}"' ) bits, mode = _handle_sym_common(alg, default_mode="cfb") t.keyBits.sym = bits t.mode.sym = mode return t class TPMT_SYM_DEF_OBJECT(TPMT_SYM_DEF): pass class TPMT_PUBLIC(TPM_OBJECT): @staticmethod def _handle_rsa(objstr, templ): templ.type = TPM2_ALG.RSA if objstr is None or objstr == "": objstr = "2048" expected = ["1024", "2048", "3072", "4096"] if objstr not in expected: raise ValueError( f'Expected keybits for RSA to be one of {expected}, got:"{objstr}"' ) keybits = int(objstr) templ.parameters.rsaDetail.keyBits = keybits return True @staticmethod def _handle_ecc(objstr, templ): templ.type = TPM2_ALG.ECC if objstr is None or objstr == "": curve = TPM2_ECC_CURVE.NIST_P256 elif objstr.startswith("_"): curve = TPM2_ECC_CURVE.parse(objstr[1:]) else: curve = TPM2_ECC_CURVE.parse(objstr) templ.parameters.eccDetail.curveID = curve templ.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL return True @staticmethod def _handle_aes(objstr, templ): templ.type = TPM2_ALG.SYMCIPHER templ.parameters.symDetail.sym.algorithm = TPM2_ALG.AES bits, mode = _handle_sym_common(objstr) templ.parameters.symDetail.sym.keyBits.sym = bits templ.parameters.symDetail.sym.mode.sym = mode return False @staticmethod def _handle_camellia(objstr, templ): templ.type = TPM2_ALG.SYMCIPHER templ.parameters.symDetail.sym.algorithm = TPM2_ALG.CAMELLIA bits, mode = _handle_sym_common(objstr) templ.parameters.symDetail.sym.keyBits.sym = bits templ.parameters.symDetail.sym.mode.sym = mode return False @staticmethod def _handle_sm4(objstr, templ): templ.type = TPM2_ALG.SYMCIPHER templ.parameters.symDetail.sym.algorithm = TPM2_ALG.SM4 bits, mode = _handle_sym_common(objstr) if bits != 128: raise ValueError(f'Expected bits to be 128, got: "{bits}"') templ.parameters.symDetail.sym.keyBits.sym = bits templ.parameters.symDetail.sym.mode.sym = mode return False @staticmethod def _handle_xor(_, templ): templ.type = TPM2_ALG.KEYEDHASH templ.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.XOR return True @staticmethod def _handle_hmac(_, templ): templ.type = TPM2_ALG.KEYEDHASH templ.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.HMAC return True @staticmethod def _handle_keyedhash(_, templ): templ.type = TPM2_ALG.KEYEDHASH templ.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.NULL return False @staticmethod def _error_on_conflicting_sign_attrs(templ): """ If the scheme is set, both the encrypt and decrypt attributes cannot be set, check to see if this is the case, and turn down: - DECRYPT - If its a signing scheme. - ENCRYPT - If its an asymmetric enc scheme. :param templ: The template to modify """ # Nothing to do if templ.parameters.asymDetail.scheme.scheme == TPM2_ALG.NULL: return is_both_set = bool(templ.objectAttributes & TPMA_OBJECT.SIGN_ENCRYPT) and bool( templ.objectAttributes & TPMA_OBJECT.DECRYPT ) # One could smarten this up to behave like tpm2-tools and turn down the attribute, but for now # error on bad attribute sets if is_both_set: raise ParserAttributeError( "Cannot set both SIGN_ENCRYPT and DECRYPT in objectAttributes" ) @staticmethod def _handle_scheme_rsa(scheme, templ): if scheme is None or len(scheme) == 0: scheme = "null" halg = "" # rsaes must match exactly takes no other params if scheme == "rsaes": templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.RSAES TPMT_PUBLIC._error_on_conflicting_sign_attrs(templ) elif scheme == "null": templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.NULL elif scheme.startswith("rsassa"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.RSASSA halg = scheme[len("rsassa") + 1 :] elif scheme.startswith("rsapss"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.RSAPSS halg = scheme[len("rsapss") + 1 :] elif scheme.startswith("oaep"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.OAEP halg = scheme[len("oaep") + 1 :] else: templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.NULL raise ValueError( f'Expected RSA scheme null or rsapss or prefix of rsapss, rsassa, got "{scheme}"' ) if halg == "": halg = "sha256" templ.parameters.asymDetail.scheme.details.anySig.hashAlg = TPM2_ALG.parse(halg) TPMT_PUBLIC._error_on_conflicting_sign_attrs(templ) return True @staticmethod def _handle_scheme_ecc(scheme, templ): if scheme is None or len(scheme) == 0: scheme = "null" halg = "" if scheme.startswith("ecdsa"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.ECDSA halg = scheme[len("ecdsa") + 1 :] elif scheme.startswith("ecdh"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.ECDH halg = scheme[len("ecdh") + 1 :] elif scheme.startswith("ecschnorr"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.ECSCHNORR halg = scheme[len("ecschnorr") + 1 :] elif scheme.startswith("ecdaa"): templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.ECDAA counter = scheme[5:] if len(scheme) > 5 else "0" hunks = counter.split("-") counter = hunks[0] halg = hunks[1] if len(hunks) > 1 else "" templ.parameters.eccDetail.scheme.details.ecdaa.count = int(counter) elif scheme == "null": templ.parameters.eccDetail.scheme.scheme = TPM2_ALG.NULL else: templ.parameters.asymDetail.scheme.scheme = TPM2_ALG.NULL raise ValueError( f'Expected EC scheme null or prefix of oaep, ecdsa, ecdh, scshnorr, ecdaa, got "{scheme}"' ) if halg == "": halg = "sha256" templ.parameters.asymDetail.scheme.details.anySig.hashAlg = TPM2_ALG.parse(halg) TPMT_PUBLIC._error_on_conflicting_sign_attrs(templ) return True @staticmethod def _handle_scheme_keyedhash(scheme, templ): if scheme is None or scheme == "": scheme = "sha256" halg = TPM2_ALG.parse(scheme) if templ.parameters.keyedHashDetail.scheme.scheme == TPM2_ALG.HMAC: templ.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = halg elif templ.parameters.keyedHashDetail.scheme.scheme == TPM2_ALG.XOR: templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.hashAlg = halg templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.kdf = ( TPM2_ALG.KDF1_SP800_108 ) else: raise ValueError( f'Expected one of HMAC or XOR, got: "{templ.parameters.keyedHashDetail.scheme.scheme}"' ) @staticmethod def _handle_scheme(scheme, templ): if templ.type == TPM2_ALG.RSA: TPMT_PUBLIC._handle_scheme_rsa(scheme, templ) elif templ.type == TPM2_ALG.ECC: TPMT_PUBLIC._handle_scheme_ecc(scheme, templ) elif templ.type == TPM2_ALG.KEYEDHASH: TPMT_PUBLIC._handle_scheme_keyedhash(scheme, templ) else: # TODO make __str__ routine for int types raise ValueError( f'Expected object to be of type RSA, ECC or KEYEDHASH, got "{templ.type}"' ) @staticmethod def _handle_asymdetail(detail, templ): if templ.type == TPM2_ALG.KEYEDHASH: if detail is not None: raise ValueError( f'Keyedhash objects cannot have asym detail, got: "{detail}"' ) return if templ.type != TPM2_ALG.RSA and templ.type != TPM2_ALG.ECC: raise ValueError( f'Expected only RSA and ECC objects to have asymdetail, got: "{templ.type}"' ) is_restricted = bool(templ.objectAttributes & TPMA_OBJECT.RESTRICTED) is_rsapss = templ.parameters.asymDetail.scheme.scheme == TPM2_ALG.RSAPSS t = TPMT_SYM_DEF.parse(detail, is_restricted, is_rsapss) templ.parameters.symDetail.sym = t @classmethod def parse( cls, alg: str = "rsa", objectAttributes: Union[ TPMA_OBJECT, int, str ] = TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS, nameAlg: Union[TPM2_ALG, int, str] = "sha256", authPolicy: bytes = None, ) -> "TPMT_PUBLIC": """Builds a TPMT_PUBLIC from a tpm2-tools like specifier strings. This builds the TPMT_PUBLIC structure which can be used in TPM2_Create and TPM2_CreatePrimary commands that map into the tpm2-tools project as tpm2 create and createprimary commandlets. Those commands take options: -G, -n, -L and -a option to specify the object to create. This method converts those options, but does not create the object like tpm2-tools. Args: alg (str): The string specifier for the objects algorithm type, bitsize, symmetric cipher and scheme. This is tpm2-tools option "-G" as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/alg.md#complex-specifiers. objectAttiributes (TPMA_OBJECT, int, str): The objects attributes whihch can either the object attributes themselves or a nice name string value. This is tpm2-tools option "-a as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/obj-attrs.md. nameAlg (TPM2_ALG, int, str): The hashing algorithm for the objects name, either the TPM2_ALG constant, integer value or a friendly name string. This is tpm2-tools option "-n" as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/alg.md#hashing-algorithms authPolicy (bytes): The policy digest of the object. This is tpm2-tools option "-L". Returns: A populated TPMT_PUBLIC for use. Raises: ValueError: If a string value is not of an expected format. Examples: .. code-block:: python TPMT_PUBLIC.parse( "ecc:ecdh-sha384", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS) TPMT_PUBLIC.parse( alg="xor:sha512", nameAlg="sha256", authPolicy=b'\xc5\x81sS\xf2\x9bc\x87r\xdf\x01\xd3\xbaowM\x96Q\xaf\x1a\xeeKEO\x82\xfeV\xf3\x13^[\x87') """ templ = TPMT_PUBLIC() if isinstance(nameAlg, str): nameAlg = TPM2_ALG.parse(nameAlg) templ.nameAlg = nameAlg if isinstance(objectAttributes, str): objectAttributes = TPMA_OBJECT.parse(objectAttributes) templ.objectAttributes = objectAttributes if authPolicy is not None: templ.authPolicy = authPolicy alg = alg.lower() hunks = alg.split(":") objstr = hunks[0].lower() scheme = hunks[1].lower() if len(hunks) > 1 else None symdetail = hunks[2].lower() if len(hunks) > 2 else None expected = ("rsa", "ecc", "aes", "camellia", "sm4", "xor", "hmac", "keyedhash") keep_processing = False prefix = tuple(filter(lambda x: objstr.startswith(x), expected)) if len(prefix) == 1: prefix = prefix[0] keep_processing = getattr(TPMT_PUBLIC, f"_handle_{prefix}")( objstr[len(prefix) :], templ ) else: raise ValueError( f'Expected object prefix to be one of {expected}, got: "{objstr}"' ) if not keep_processing: if scheme: raise ValueError( f'{prefix} objects cannot have additional specifiers, got: "{scheme}"' ) return templ # at this point we either have scheme as a scheme or an asym detail try: TPMT_PUBLIC._handle_scheme(scheme, templ) except ValueError as e: # nope try it as asymdetail symdetail = scheme TPMT_PUBLIC._handle_asymdetail(symdetail, templ) return templ @classmethod def from_pem( cls, data: bytes, nameAlg: Union[TPM2_ALG, int] = TPM2_ALG.SHA256, objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), symmetric: TPMT_SYM_DEF_OBJECT = None, scheme: TPMT_ASYM_SCHEME = None, password: bytes = None, ) -> "TPMT_PUBLIC": """Decode the public part from standard key encodings. Currently supports PEM, DER and SSH encoded public keys. Args: data (bytes): The encoded public key. nameAlg (TPM2_ALG, int): The name algorithm for the public area, default is TPM2_ALG.SHA256. objectAttributes (TPMA_OBJECT, int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). symmetric (TPMT_SYM_DEF_OBJECT) optional: The symmetric definition to use for the public area, default is None. scheme (TPMT_ASYM_SCHEME) optional: The signing/key exchange scheme to use for the public area, default is None. password (bytes) optional: The password used to decrypt the key, default is None. Returns: Returns a TPMT_PUBLIC instance. Raises: ValueError: If key parameters are not supported. Example: .. code-block:: python ecc_key_pem = open('path/to/myecckey.pem').read().encode() TPMT_PUBLIC.from_pem(ecc_key_pem) """ p = cls() _public_from_encoding(data, p, password=password) p.nameAlg = nameAlg if isinstance(objectAttributes, str): objectAttributes = TPMA_OBJECT.parse(objectAttributes) p.objectAttributes = objectAttributes if symmetric is None: p.parameters.asymDetail.symmetric.algorithm = TPM2_ALG.NULL elif isinstance(symmetric, str): TPMT_PUBLIC._handle_asymdetail(symmetric, p) else: p.parameters.asymDetail.symmetric = symmetric if scheme is None: p.parameters.asymDetail.scheme.scheme = TPM2_ALG.NULL elif isinstance(scheme, str): TPMT_PUBLIC._handle_scheme(scheme, p) else: p.parameters.asymDetail.scheme = scheme if p.type == TPM2_ALG.ECC: p.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL return p def to_pem(self) -> bytes: """Encode the public key as PEM encoded ASN.1. Returns: Returns the PEM encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.publicArea.to_pem() """ return _public_to_pem(self, "pem") def to_der(self) -> bytes: """Encode the public key as DER encoded ASN.1. Returns: Returns the DER encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.publicArea.to_der() """ return _public_to_pem(self, "der") def to_ssh(self) -> bytes: """Encode the public key in OpenSSH format Returns: Returns the OpenSSH encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.publicArea.to_ssh() """ return _public_to_pem(self, "ssh") def get_name(self) -> TPM2B_NAME: """Get the TPM name of the public area. This function requires a populated TPMT_PUBLIC and will NOT go to the TPM to retrieve the name, and instead calculates it manually. Returns: Returns TPM2B_NAME. Raises: ValueError: Unsupported name digest algorithm. """ name = _getname(self) return TPM2B_NAME(name) class TPM2B_ATTEST(TPM2B_SIMPLE_OBJECT): pass class TPM2B_CONTEXT_DATA(TPM2B_SIMPLE_OBJECT): pass class TPM2B_CONTEXT_SENSITIVE(TPM2B_SIMPLE_OBJECT): pass class TPM2B_CREATION_DATA(TPM_OBJECT): pass class TPM2B_DATA(TPM2B_SIMPLE_OBJECT): pass class TPM2B_DIGEST(TPM2B_SIMPLE_OBJECT): pass class TPM2B_ECC_PARAMETER(TPM2B_SIMPLE_OBJECT): pass class TPM2B_ECC_POINT(TPM_OBJECT): pass class TPM2B_ENCRYPTED_SECRET(TPM2B_SIMPLE_OBJECT): pass class TPM2B_EVENT(TPM2B_SIMPLE_OBJECT): pass class TPM2B_ID_OBJECT(TPM2B_SIMPLE_OBJECT): pass class TPM2B_IV(TPM2B_SIMPLE_OBJECT): pass class TPM2B_MAX_BUFFER(TPM2B_SIMPLE_OBJECT): pass class TPM2B_MAX_NV_BUFFER(TPM2B_SIMPLE_OBJECT): pass class TPM2B_NV_PUBLIC(TPM_OBJECT): def get_name(self) -> TPM2B_NAME: """Get the TPM name of the NV public area. This function requires a populated TPM2B_NV_PUBLIC and will NOT go to the TPM to retrieve the name, and instead calculates it manually. Returns: Returns TPM2B_NAME. Raises: ValueError: Unsupported name digest algorithm. """ return self.nvPublic.get_name() class TPM2B_PRIVATE(TPM2B_SIMPLE_OBJECT): pass class TPM2B_PRIVATE_KEY_RSA(TPM2B_SIMPLE_OBJECT): pass class TPM2B_PRIVATE_VENDOR_SPECIFIC(TPM2B_SIMPLE_OBJECT): pass class TPM2B_PUBLIC(TPM_OBJECT): @classmethod def from_pem( cls, data: bytes, nameAlg: Union[TPM2_ALG, int] = TPM2_ALG.SHA256, objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), symmetric: TPMT_SYM_DEF_OBJECT = None, scheme: TPMT_ASYM_SCHEME = None, password: bytes = None, ) -> "TPM2B_PUBLIC": """Decode the public part from standard key encodings. Currently supports PEM, DER and SSH encoded public keys. Args: data (bytes): The encoded public key. nameAlg (TPM2_ALG, int): The name algorithm for the public area, default is TPM2_ALG.SHA256. objectAttributes (TPMA_OBJECT, int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). symmetric (TPMT_SYM_DEF_OBJECT) optional: The symmetric definition to use for the public area, default is None. scheme (TPMT_ASYM_SCHEME) optional: The signing/key exchange scheme to use for the public area, default is None. password (bytes) optional: The password used to decrypt the key, default is None. Returns: Returns a TPMT_PUBLIC instance. Raises: ValueError: If key parameters are not supported. Example: .. code-block:: python ecc_key_pem = open('path/to/myecckey.pem').read().encode() TP2B_PUBLIC.from_pem(ecc_key_pem) """ pa = TPMT_PUBLIC.from_pem( data, nameAlg, objectAttributes, symmetric, scheme, password ) p = cls(publicArea=pa) return p def to_pem(self) -> bytes: """Encode the public key as PEM encoded ASN.1. Returns: Returns the PEM encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.to_pem() """ return self.publicArea.to_pem() def to_der(self) -> bytes: """Encode the public key as DER encoded ASN.1. Returns: Returns the DER encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.to_der() """ return self.publicArea.to_der() def to_ssh(self) -> bytes: """Encode the public key in OpenSSH format Returns: Returns the OpenSSH encoded key as bytes. Raises: ValueError: If key type is not supported. Example: .. code-block:: python with ESAPI() as e: # public parameter is index 1 in the return tuple pub = e.create_primary(None)[1] pub.to_ssh() """ return self.publicArea.to_ssh() def get_name(self) -> TPM2B_NAME: """Get the TPM name of the public area. This function requires a populated TPM2B_PUBLIC and will NOT go to the TPM to retrieve the name, and instead calculates it manually. Returns: Returns TPM2B_NAME. Raises: ValueError: Unsupported name digest algorithm. """ return self.publicArea.get_name() @classmethod def parse( cls, alg="rsa", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS, nameAlg="sha256", authPolicy=None, ) -> "TPM2B_PUBLIC": """Builds a TPM2B_PUBLIC from a tpm2-tools like specifier strings. This builds the TPM2B_PUBLIC structure which can be used in TPM2_Create and TPM2_CreatePrimary commands that map into the tpm2-tools project as tpm2 create and createprimary commandlets. Those commands take options: -G, -n, -L and -a option to specify the object to create. This method converts those options, but does not create the object like tpm2-tools. Args: alg (str): The string specifier for the objects algorithm type, bitsize, symmetric cipher and scheme. This is tpm2-tools option "-G" as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/alg.md#complex-specifiers. objectAttiributes (TPMA_OBJECT, int, str): The objects attributes whihch can either the object attributes themselves or a nice name string value. This is tpm2-tools option "-a as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/obj-attrs.md. nameAlg (TPM2_ALG, int, str): The hashing algorithm for the objects name, either the TPM2_ALG constant, integer value or a friendly name string. This is tpm2-tools option "-n" as described in: https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/alg.md#hashing-algorithms authPolicy (bytes): The policy digest of the object. This is tpm2-tools option "-L". Returns: A populated TPMT_PUBLIC for use. Raises: ValueError: If a string value is not of an expected format. Examples: .. code-block:: python TPM2B_PUBLIC.parse( "ecc:ecdh-sha384", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS) TPM2B_PUBLIC.parse( alg="xor:sha512", nameAlg="sha256", authPolicy=b'\xc5\x81sS\xf2\x9bc\x87r\xdf\x01\xd3\xbaowM\x96Q\xaf\x1a\xeeKEO\x82\xfeV\xf3\x13^[\x87') """ return cls(TPMT_PUBLIC.parse(alg, objectAttributes, nameAlg, authPolicy)) class TPM2B_PUBLIC_KEY_RSA(TPM2B_SIMPLE_OBJECT): pass class TPMT_KEYEDHASH_SCHEME(TPM_OBJECT): pass class TPM2B_SENSITIVE(TPM_OBJECT): @classmethod def from_pem( cls, data: bytes, password: Optional[bytes] = None ) -> "TPM2B_SENSITIVE": """Decode the private part from standard key encodings. Currently supports PEM, DER and SSH encoded private keys. Args: data (bytes): The encoded key as bytes. password (bytes): The password used to decrypt the key, default is None. Returns: Returns an instance of TPM2B_SENSITIVE. Raises: ValueError: If key parameters are not supported. Example: .. code-block:: python rsa_private_key = open('path/to/my/rsaprivatekey.pem').read().encode() TPM2B_SENSITIVE.from_pem(rsa_private_key) """ p = TPMT_SENSITIVE.from_pem(data, password) return cls(sensitiveArea=p) @classmethod def keyedhash_from_secret( cls, secret: bytes, nameAlg: Union[TPM2_ALG, int] = TPM2_ALG.SHA256, objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), scheme: TPMT_KEYEDHASH_SCHEME = None, seed: bytes = None, ) -> Tuple["TPM2B_SENSITIVE", TPM2B_PUBLIC]: """Generate the private and public part for a keyed hash object from a secret. Args: secret (bytes): The HMAC key / data to be sealed. nameAlg (TPM2_ALG, int): The name algorithm for the public part, default is TPM2_ALG.SHA256. objectAttributes (TPMA_OBJECT, int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). scheme (TPMT_KEYEDHASH_SCHEME) optional: The signing/key exchange scheme to use for the public area, default is None. seed (bytes) optional: The obfuscate value, default is a randomized value. Returns: A tuple of TPM2B_SENSITIVE and TPM2B_PUBLIC Raises: ValueError: If key parameters are not supported. Example: .. code-block:: python secret = b"secret key" scheme = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.HMAC) scheme.details.hmac.hashAlg = TPM2_ALG.SHA256 (sens, pub) = TPM2B_SENSITIVE.keyedhash_from_secret(secret, scheme=scheme) """ sa, pa = TPMT_SENSITIVE.keyedhash_from_secret( secret, nameAlg, objectAttributes, scheme, seed ) priv = TPM2B_SENSITIVE(sensitiveArea=sa) pub = TPM2B_PUBLIC(publicArea=pa) return (priv, pub) @classmethod def symcipher_from_secret( cls, secret: bytes, algorithm: Union[TPM2_ALG, int] = TPM2_ALG.AES, mode: Union[TPM2_ALG, int] = TPM2_ALG.CFB, nameAlg: Union[TPM2_ALG, int] = TPM2_ALG.SHA256, objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), seed: bytes = None, ) -> Tuple["TPM2B_SENSITIVE", TPM2B_PUBLIC]: """Generate the private and public part for a symcipher object from a secret. Args: secret (bytes): the symmetric key. algorithm (TPM2_ALG, int): The symmetric cipher algorithm to use, default is TPM2_ALG.AES. mode (TPM2_ALG, int): The symmetric mode to use, default is TPM2_ALG.CFB. nameAlg (TPM2_ALG, int): The name algorithm for the public part, default is TPM2_ALG.SHA256. objectAttributes (TPMA_OBJECT, int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). seed (bytes) optional: The obfuscate value, default is a randomized value. Returns: A tuple of TPM2B_SENSITIVE and TPM2B_PUBLIC Example: .. code-block:: python secret = b"\xF1" * 32 sens, pub = TPM2B_SENSITIVE.symcipher_from_secret(secret) """ sa, pa = TPMT_SENSITIVE.symcipher_from_secret( secret, algorithm, mode, nameAlg, objectAttributes, seed ) priv = TPM2B_SENSITIVE(sensitiveArea=sa) pub = TPM2B_PUBLIC(publicArea=pa) return (priv, pub) def to_pem(self, public: TPMT_PUBLIC, password=None) -> bytes: """Encode the key as PEM encoded ASN.1. Args: public(TPMT_PUBLIC): The corresponding public key. password(bytes): An optional password for encrypting the PEM with. Returns: Returns the PEM encoding as bytes. Raises: ValueError: Unsupported key type. Example: .. code-block:: python rsa_private_key = open('path/to/my/rsaprivatekey.pem').read().encode() priv = TPM2B_SENSITIVE.from_pem(rsa_private_key) pub = TPM2B_PUBLIC.from_pem(rsa_private_key) priv.to_pem(pub.publicArea) """ return self.sensitiveArea.to_pem(public, password) def to_der(self, public: TPMT_PUBLIC) -> bytes: """Encode the key as DER encoded ASN.1. public(TPMT_PUBLIC): The corresponding public key. Returns: Returns the DER encoding as bytes. Raises: ValueError: Unsupported key type. Example: .. code-block:: python rsa_private_key = open('path/to/my/rsaprivatekey.pem').read().encode() priv = TPM2B_SENSITIVE.from_pem(rsa_private_key) pub = TPM2B_PUBLIC.from_pem(rsa_private_key) priv.to_der(pub.publicArea) """ return self.sensitiveArea.to_der(public) def to_ssh(self, public: TPMT_PUBLIC, password: bytes = None) -> bytes: """Encode the key as OPENSSH PEM format. Args: public(TPMT_PUBLIC): The corresponding public key. password(bytes): An optional password for encrypting the PEM with. Returns: Returns the PEM OPENSSH encoding as bytes. Raises: ValueError: Unsupported key type. Example: .. code-block:: python rsa_private_key = open('path/to/my/rsaprivatekey.pem').read().encode() priv = TPM2B_SENSITIVE.from_pem(rsa_private_key) pub = TPM2B_PUBLIC.from_pem(rsa_private_key) priv.to_ssh(pub.publicArea) """ return self.sensitiveArea.to_ssh(public, password=password) class TPM2B_SENSITIVE_CREATE(TPM_OBJECT): pass class TPM2B_SENSITIVE_DATA(TPM2B_SIMPLE_OBJECT): pass class TPM2B_SYM_KEY(TPM2B_SIMPLE_OBJECT): pass class TPM2B_TEMPLATE(TPM2B_SIMPLE_OBJECT): pass class TPML_AC_CAPABILITIES(TPML_OBJECT): pass class TPML_ALG(TPML_OBJECT): @classmethod def parse(cls, algorithms: str) -> "TPML_ALG": """Convert an comma separated list of algorithm friendly string names to a list of numeric constants. Friendly algorithm names are the constants representing algorithms found in the TPM2_ALG class. The string identifiers are those understood by TPM2_ALG.parse. Args: algorithms(str): A comma separated list of algorithm friendly names. May be a list of one item with no comma. Returns: A populated TPML_ALG Raises: ValueError: Invalid algorithms list. Example: .. code-block:: python TPML_ALG("aes") TPML_ALG("aes,sha256") """ if algorithms is None or len(algorithms) == 0: raise ValueError( f"Expected algorithms to be not None or len > 0, got: {algorithms}" ) alglist = [] for a in algorithms.split(","): a = a.strip() if len(a) > 0: alglist.append(TPM2_ALG.parse(a)) if len(alglist) == 0: raise ValueError(f'No algorithms found in algorithms, got "{algorithms}"') return TPML_ALG(alglist) class TPML_ALG_PROPERTY(TPML_OBJECT): pass class TPML_CC(TPML_OBJECT): pass class TPML_CCA(TPML_OBJECT): pass class TPML_DIGEST(TPML_OBJECT): pass class TPML_DIGEST_VALUES(TPML_OBJECT): pass class TPML_ECC_CURVE(TPML_OBJECT): pass class TPML_HANDLE(TPML_OBJECT): pass class TPML_INTEL_PTT_PROPERTY(TPML_OBJECT): pass class TPML_PCR_SELECTION(TPML_OBJECT): @staticmethod def parse(selections: str) -> "TPML_PCR_SELECTION": """Convert a PCR selection string into the TPML_PCR_SELECTION data structure. PCR Bank Selection lists follow the below specification: :: :[,] or :all multiple banks may be separated by '+'. For Example "sha1:3,4+sha256:all", will select PCRs 3 and 4 from the SHA1 bank and PCRs 0 to 23 from the SHA256 bank. Args: algorithms(str): A comma separated list of algorithm friendly names. May be a list of one item with no comma. Returns: A populated TPML_PCR_SELECTION Raises: ValueError: Invalid algorithms list. Example: .. code-block:: python TPML_PCR_SELECTION.parse("sha256:1,3,5,7") TPML_PCR_SELECTION.parse("sha1:3,4+sha256:all") """ if selections is None or len(selections) == 0: return TPML_PCR_SELECTION() selectors = selections.split("+") if "+" in selections else [selections] if len(selectors) - 1 != selections.count("+"): raise ValueError( f"Malformed PCR bank selection list (unbalanced +), got: {selections}" ) for x in selectors: if len(x) == 0: raise ValueError( f"Malformed PCR bank selection list (unbalanced +), got: {selections}" ) count = len(selectors) if count > lib.TPM2_NUM_PCR_BANKS: raise ValueError( f"PCR Selection list greater than {lib.TPM2_NUM_PCR_BANKS}, " f"got {len(selectors)}" ) selections = [TPMS_PCR_SELECTION.parse(x) for x in selectors] return TPML_PCR_SELECTION(selections) class TPML_TAGGED_PCR_PROPERTY(TPML_OBJECT): pass class TPML_TAGGED_TPM_PROPERTY(TPML_OBJECT): pass class TPMS_AC_OUTPUT(TPM_OBJECT): pass class TPMS_ALGORITHM_DESCRIPTION(TPM_OBJECT): pass class TPMS_ALGORITHM_DETAIL_ECC(TPM_OBJECT): pass class TPMS_ALG_PROPERTY(TPM_OBJECT): pass class TPMS_ASYM_PARMS(TPM_OBJECT): pass class TPMU_ATTEST(TPMU_OBJECT): pass class TPMS_ATTEST(TPM_OBJECT): pass class TPMS_AUTH_COMMAND(TPM_OBJECT): pass class TPMS_AUTH_RESPONSE(TPM_OBJECT): pass class TPMU_CAPABILITIES(TPMU_OBJECT): pass class TPMS_CAPABILITY_DATA(TPM_OBJECT): pass class TPMS_CERTIFY_INFO(TPM_OBJECT): pass class TPMS_CLOCK_INFO(TPM_OBJECT): pass class TPMS_COMMAND_AUDIT_INFO(TPM_OBJECT): pass class TPMS_CONTEXT(TPM_OBJECT): @classmethod def from_tools(cls, data: bytes) -> "TPMS_CONTEXT": """Unmarshal a tpm2-tools context blob. Args: data (bytes): The bytes from a tpm2-tools context file. Returns: Returns a TPMS_CONTEXT instance. Raises: ValueError: if the header contains bad values """ magic = int.from_bytes(data[0:4], byteorder="big") if magic != 0xBADCC0DE: raise ValueError(f"bad magic, expected 0xBADCC0DE, got 0x{magic:X}") version = int.from_bytes(data[4:8], byteorder="big") if version not in (1, 2): raise ValueError(f"bad version, expected 1 or 2, got {version}") ctx = cls() if version == 2: # tpm2-tools version 2 context format is: # magic + version 2 + TPM2_SE + TPM2_ALG + version 1 context # as we can't store the session type or digest alg, just skip them return cls.from_tools(data[11:]) ctx.hierarchy = int.from_bytes(data[8:12], byteorder="big") ctx.savedHandle = int.from_bytes(data[12:16], byteorder="big") ctx.sequence = int.from_bytes(data[16:24], byteorder="big") ctx.contextBlob, _ = TPM2B_CONTEXT_DATA.unmarshal(data[24:]) return ctx def to_tools(self, session_type: TPM2_SE = None, auth_hash: TPM2_ALG = None): """Marshal the context into a tpm2-tools context blob. Args: session_type (TPM2_SE): The session type, default is None. auth_hash (TPM2_ALG): The session hash algorithm, default is None. Note: Both session_type and auth_hash are required for HMAC and policy sessions. Returns: The context blob as bytes Raises: TypeError: if session_type and auth_hash is missing for a session context. """ handle_range = TPM2_HR.RANGE_MASK & self.savedHandle if handle_range in (TPM2_HR.HMAC_SESSION, TPM2_HR.POLICY_SESSION) and ( session_type is None or auth_hash is None ): raise TypeError( "session_type and auth_hash most be defined for session contexts" ) version = 1 if session_type is not None: version = 2 data = b"" if version == 2: data = int(0xBADCC0DE).to_bytes(4, "big") + version.to_bytes(4, "big") data = data + session_type.to_bytes(1, "big") data = data + auth_hash.to_bytes(2, "big") data = data + int(0xBADCC0DE).to_bytes(4, "big") + int(1).to_bytes(4, "big") data = data + self.hierarchy.to_bytes(4, "big") data = data + self.savedHandle.to_bytes(4, "big") data = data + self.sequence.to_bytes(8, "big") data = data + self.contextBlob.marshal() return data class TPMS_CONTEXT_DATA(TPM_OBJECT): pass class TPMS_CREATION_DATA(TPM_OBJECT): pass class TPMS_CREATION_INFO(TPM_OBJECT): pass class TPMS_ECC_PARMS(TPM_OBJECT): pass class TPMS_ECC_POINT(TPM_OBJECT): pass class TPMS_EMPTY(TPM_OBJECT): pass class TPMS_ID_OBJECT(TPM_OBJECT): pass class TPMS_KEYEDHASH_PARMS(TPM_OBJECT): pass class TPMS_NV_CERTIFY_INFO(TPM_OBJECT): pass class TPMS_NV_PIN_COUNTER_PARAMETERS(TPM_OBJECT): pass class TPMS_NV_PUBLIC(TPM_OBJECT): def get_name(self) -> TPM2B_NAME: """Get the TPM name of the NV public area. Returns: Returns TPM2B_NAME. """ name = _getname(self) return TPM2B_NAME(name) class TPMS_PCR_SELECT(TPM_OBJECT): pass class TPMS_PCR_SELECTION(TPM_OBJECT): def __init__(self, pcrs=None, **kwargs): super().__init__(**kwargs) if not pcrs: return if bool(self.hash) != bool(pcrs): raise ValueError("hash and pcrs MUST be specified") self._cdata.sizeofSelect = 3 if pcrs == "all" or (len(pcrs) == 1 and pcrs[0] == "all"): self._cdata.pcrSelect[0] = 0xFF self._cdata.pcrSelect[1] = 0xFF self._cdata.pcrSelect[2] = 0xFF return for pcr in pcrs: if pcr < 0 or pcr > lib.TPM2_PCR_LAST: raise ValueError(f"PCR Index out of range, got {pcr}") self._cdata.pcrSelect[pcr // 8] |= 1 << (pcr % 8) @staticmethod def parse(selection: str) -> "TPMS_PCR_SELECTION": """Given a PCR selection string populate a TPMS_PCR_SELECTION structure. A PCR Bank selection lists: :: :[,] or :all For Example "sha1:3,4", will select PCRs 3 and 4 from the SHA1 bank. Args: selection(str): A PCR selection string. Returns: A populated TPMS_PCR_SELECTION Raises: ValueError: Invalid PCR specification. Example: .. code-block:: python TPMS_PCR_SELECTION.parse("sha256:1,3,5,7") TPMS_PCR_SELECTION.parse("sha1:all") """ if selection is None or len(selection) == 0: raise ValueError( f'Expected selection to be not None and len > 0, got: "{selection}"' ) hunks = [x.strip() for x in selection.split(":")] if len(hunks) != 2: raise ValueError(f"PCR Selection malformed, got {selection}") try: halg = int(hunks[0], 0) except ValueError: halg = TPM2_ALG.parse(hunks[0]) if hunks[1] != "all": try: pcrs = [int(x.strip(), 0) for x in hunks[1].split(",")] except ValueError: raise ValueError(f"Expected PCR number, got {hunks[1]}") else: pcrs = hunks[1] return TPMS_PCR_SELECTION(hash=halg, pcrs=pcrs) class TPMS_QUOTE_INFO(TPM_OBJECT): pass class TPMS_RSA_PARMS(TPM_OBJECT): pass class TPMS_SCHEME_ECDAA(TPM_OBJECT): pass class TPMS_SCHEME_HASH(TPM_OBJECT): pass class TPMS_SCHEME_XOR(TPM_OBJECT): pass class TPMS_SENSITIVE_CREATE(TPM_OBJECT): pass class TPMS_SESSION_AUDIT_INFO(TPM_OBJECT): pass class TPMS_SIGNATURE_ECC(TPM_OBJECT): pass class TPMS_SIGNATURE_RSA(TPM_OBJECT): pass class TPMS_SYMCIPHER_PARMS(TPM_OBJECT): pass class TPMS_TAGGED_PCR_SELECT(TPM_OBJECT): pass class TPMS_TAGGED_PROPERTY(TPM_OBJECT): pass class TPMS_TIME_ATTEST_INFO(TPM_OBJECT): pass class TPMS_TIME_INFO(TPM_OBJECT): pass class TPMT_ECC_SCHEME(TPM_OBJECT): pass class TPMU_ASYM_SCHEME(TPMU_OBJECT): pass class TPMU_KDF_SCHEME(TPMU_OBJECT): pass class TPMT_KDF_SCHEME(TPM_OBJECT): pass class TPMT_TK_CREATION(TPM_OBJECT): pass class TPMT_RSA_SCHEME(TPM_OBJECT): pass class TPMU_SYM_KEY_BITS(TPMU_OBJECT): pass class TPMU_SYM_MODE(TPMU_OBJECT): pass class TPM2B_AUTH(TPM2B_SIMPLE_OBJECT): pass class TPM2B_NONCE(TPM2B_SIMPLE_OBJECT): pass class TPMU_PUBLIC_ID(TPMU_OBJECT): pass class TPMT_SENSITIVE(TPM_OBJECT): @classmethod def from_pem(cls, data, password: Optional[bytes] = None): """Decode the private part from standard key encodings. Currently supports PEM, DER and SSH encoded private keys. Args: data (bytes): The encoded key as bytes. password (bytes): The password used to decrypt the key, default is None. Returns: Returns an instance of TPMT_SENSITIVE. """ p = cls() _private_from_encoding(data, p, password) return p @classmethod def keyedhash_from_secret( cls, secret, nameAlg=TPM2_ALG.SHA256, objectAttributes=( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), scheme: Optional[TPMT_KEYEDHASH_SCHEME] = None, seed: Optional[bytes] = None, ): """Generate the private and public part for a keyed hash object from a secret. Args: secret (bytes): The HMAC key / data to be sealed. nameAlg (int): The name algorithm for the public part, default is TPM2_ALG.SHA256. objectAttributes (int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). scheme (TPMT_KEYEDHASH_SCHEME): The signing/key exchange scheme to use for the public area, default is None. seed (bytes): The obfuscate value, default is a randomized value. Returns: A tuple of of TPMT_SENSITIVE and TPMT_PUBLIC """ pub = TPMT_PUBLIC( type=TPM2_ALG.KEYEDHASH, nameAlg=nameAlg, objectAttributes=objectAttributes ) if scheme is None: pub.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.NULL else: pub.parameters.keyedHashDetail.scheme = scheme digsize = _get_digest_size(nameAlg) if seed and len(seed) != digsize: raise ValueError( f"invalid seed size, expected {digsize} but got {len(seed)}" ) elif not seed: seed = secrets.token_bytes(digsize) pub.unique.keyedHash = _calculate_sym_unique(nameAlg, secret, seed) priv = cls(sensitiveType=TPM2_ALG.KEYEDHASH) priv.sensitive.bits = secret priv.seedValue = seed return (priv, pub) @classmethod def symcipher_from_secret( cls, secret, algorithm=TPM2_ALG.AES, mode=TPM2_ALG.CFB, nameAlg=TPM2_ALG.SHA256, objectAttributes=( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), seed: Optional[bytes] = None, ): """ Generate the private and public part for a symcipher object from a secret. Args: secret (bytes): the symmetric key. algorithm (int): The symmetric cipher algorithm to use, default is TPM2_ALG.AES. mode (int): The symmetric mode to use, default is TPM2_ALG.CFB. nameAlg (int): The name algorithm for the public part, default is TPM2_ALG.SHA256. objectAttributes (int): The object attributes for the public area, default is (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH). seed (bytes): The obfuscate value, default is a randomized value. Returns: A tuple of TPMT_SENSITIVE and TPMT_PUBLIC """ nbits = len(secret) * 8 if algorithm == TPM2_ALG.SM4 and nbits != 128: raise ValueError(f"invalid key size, expected 128, got {nbits}") elif nbits not in (128, 192, 256): raise ValueError( f"invalid key size, expected 128, 192 or 256 bits, got {nbits}" ) pub = TPMT_PUBLIC( type=TPM2_ALG.SYMCIPHER, nameAlg=nameAlg, objectAttributes=objectAttributes ) pub.parameters.symDetail.sym.keyBits.sym = nbits pub.parameters.symDetail.sym.algorithm = algorithm pub.parameters.symDetail.sym.mode.sym = mode digsize = _get_digest_size(nameAlg) if seed and len(seed) != digsize: raise ValueError( f"invalid seed size, expected {digsize} but got {len(seed)}" ) elif not seed: seed = secrets.token_bytes(digsize) pub.unique.sym = _calculate_sym_unique(nameAlg, secret, seed) priv = cls(sensitiveType=TPM2_ALG.SYMCIPHER) priv.sensitive.bits = secret priv.seedValue = seed return (priv, pub) def _serialize( self, encoding: str, public: TPMT_PUBLIC, format: str = serialization.PrivateFormat.TraditionalOpenSSL, password: bytes = None, ): k = private_to_key(self, public) enc_alg = ( serialization.NoEncryption() if password is None else serialization.BestAvailableEncryption(password) ) data = k.private_bytes( encoding=encoding, format=format, encryption_algorithm=enc_alg ) return data def to_pem(self, public: TPMT_PUBLIC, password: bytes = None): """Encode the key as PEM encoded ASN.1. public(TPMT_PUBLIC): The corresponding public key. password(bytes): An optional password for encrypting the PEM with. Returns: Returns the PEM encoding as bytes. """ return self._serialize(serialization.Encoding.PEM, public, password=password) def to_der(self, public: TPMT_PUBLIC): """Encode the key as DER encoded ASN.1. public(TPMT_PUBLIC): The corresponding public key. Returns: Returns the DER encoding as bytes. """ return self._serialize(serialization.Encoding.DER, public) def to_ssh(self, public: TPMT_PUBLIC, password: bytes = None): """Encode the key as SSH format. public(TPMT_PUBLIC): The corresponding public key. password(bytes): An optional password for encrypting the PEM with. Returns: Returns the DER encoding as bytes. """ return self._serialize( serialization.Encoding.PEM, public, format=serialization.PrivateFormat.OpenSSH, password=password, ) class TPMU_SENSITIVE_COMPOSITE(TPMU_OBJECT): pass class TPMU_SCHEME_KEYEDHASH(TPMU_OBJECT): pass class TPMT_RSA_DECRYPT(TPM_OBJECT): pass class TPMT_TK_HASHCHECK(TPM_OBJECT): pass class TPMT_HA(TPM_OBJECT): def __bytes__(self) -> bytes: """Returns the digest field as bytes. If the hashAlg field is TPM2_ALG.NULL, it returns bytes object of len 0. Return: The digest field as bytes. """ if self.hashAlg == TPM2_ALG.NULL: return b"" ds = _get_digest_size(self.hashAlg) return bytes(self.digest.sha512[0:ds]) class TPMU_HA(TPMU_OBJECT): pass class TPMT_SIG_SCHEME(TPM_OBJECT): pass class TPMU_SIGNATURE(TPMU_OBJECT): pass class TPMT_SIGNATURE(TPM_OBJECT): def verify_signature(self, key, data, prehashed=False): """ Verify a TPM generated signature against a key. Args: key (TPMT_PUBLIC, TPM2B_PUBLIC or bytes): The key to verify against, bytes for HMAC, the public part for asymmetric key. data (bytes): The signed data to verify or the digest if prehashed is True. prehashed: (bool): If True the data should be the digest of the signed data, defaults to False. Raises: :py:class:`cryptography.exceptions.InvalidSignature`: when the signature doesn't match the data. """ _verify_signature(self, key, data, prehashed) def __bytes__(self): """Return the underlying bytes for the signature. For RSA and HMAC signatures return the signature bytes, for ECDSA return a ASN.1 encoded signature. Raises: TypeError: when the signature algorithm is unsupported. """ return _get_signature_bytes(self) class TPMU_SIG_SCHEME(TPMU_OBJECT): pass class TPMT_TK_VERIFIED(TPM_OBJECT): pass class TPM2B_TIMEOUT(TPM_OBJECT): pass class TPMT_TK_AUTH(TPM_OBJECT): pass class TPM2B_OPERAND(TPM2B_SIMPLE_OBJECT): pass class TPMS_SIG_SCHEME_RSASSA(TPM_OBJECT): pass class TPMS_SIG_SCHEME_RSAPSS(TPM_OBJECT): pass class TPMS_SIG_SCHEME_ECDSA(TPM_OBJECT): pass class TPMS_SIG_SCHEME_SM2(TPM_OBJECT): pass class TPMS_SIG_SCHEME_ECSCHNORR(TPM_OBJECT): pass class TPMS_SIG_SCHEME_ECDAA(TPM_OBJECT): pass class TPMS_SCHEME_HMAC(TPM_OBJECT): pass if _lib_version_atleast("tss2-policy", "4.0.0"): class TSS2_OBJECT(TPM_OBJECT): pass class TSS2_POLICY_PCR_SELECTIONS(TPM_OBJECT): pass class TSS2_POLICY_PCR_SELECTION(TPM_OBJECT): pass tpm2-pytss-3.0.0-rc0/src/tpm2_pytss/utils.py000066400000000000000000000422441506405471500207000ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 from .internal.crypto import ( _kdfa, _get_digest, _symdef_to_crypt, _secret_to_seed, _generate_seed, _decrypt, _encrypt, _check_hmac, _hmac, _get_digest_size, ) from .types import * from .ESAPI import ESAPI from .constants import ( ESYS_TR, TPM2_CAP, TPM2_PT_NV, TPM2_ECC, TPM2_PT, TPM2_RH, ) from .internal.templates import ek_template from .TSS2_Exception import TSS2_Exception from cryptography.hazmat.primitives import constant_time as ct from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend from typing import Optional, Tuple, Callable, List import secrets def make_credential( public: TPM2B_PUBLIC, credential: bytes, name: TPM2B_NAME ) -> Tuple[TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET]: """Encrypts credential for use with activate_credential Args: public (TPMT_PUBLIC): The public area of the activation key credential (bytes): The credential to be encrypted name (bytes): The name of the key associated with the credential Returns: A tuple of (TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET) Raises: ValueError: If the public key type is not supported """ if isinstance(public, TPM2B_PUBLIC): public = public.publicArea if isinstance(credential, bytes): credential = TPM2B_DIGEST(buffer=credential) if isinstance(name, TPM2B_SIMPLE_OBJECT): name = bytes(name) seed, enc_seed = _generate_seed(public, b"IDENTITY\x00") (cipher, symmode, symbits) = _symdef_to_crypt( public.parameters.asymDetail.symmetric ) symkey = _kdfa(public.nameAlg, seed, b"STORAGE", name, b"", symbits) enc_cred = _encrypt(cipher, symmode, symkey, credential.marshal()) halg = _get_digest(public.nameAlg) hmackey = _kdfa(public.nameAlg, seed, b"INTEGRITY", b"", b"", halg.digest_size * 8) outerhmac = _hmac(halg, hmackey, enc_cred, name) hmacdata = TPM2B_DIGEST(buffer=outerhmac).marshal() credblob = TPM2B_ID_OBJECT(credential=hmacdata + enc_cred) secret = TPM2B_ENCRYPTED_SECRET(secret=enc_seed) return (credblob, secret) def credential_to_tools( id_object: Union[TPM2B_ID_OBJECT, bytes], encrypted_secret: Union[TPM2B_ENCRYPTED_SECRET, bytes], ) -> bytes: """ Converts an encrypted credential and an encrypted secret to a format that TPM2-tools can handle. The output can be used in the credential-blob parameter of the tpm2_activatecredential command. Args: id_object: The encrypted credential area. encrypted_secret: The encrypted secret. Returns: A credential blob in byte form that can be used by TPM2-tools. """ data = bytearray() # Add the header, consisting of the magic and the version. data.extend(int(0xBADCC0DE).to_bytes(4, "big") + int(1).to_bytes(4, "big")) if isinstance(id_object, bytes): id_object = TPM2B_ID_OBJECT(id_object) if isinstance(encrypted_secret, bytes): encrypted_secret = TPM2B_ENCRYPTED_SECRET(encrypted_secret) # Add the id object and encrypted secret. data.extend(id_object.marshal()) data.extend(encrypted_secret.marshal()) return bytes(data) def tools_to_credential( credential_blob: bytes, ) -> Tuple[TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET]: """ Convert a TPM2-tools compatible credential blob. Args: credential_blob: A TPM2-tools compatible credential blob. Returns: A tuple of (TPM2B_ID_OBJECT, TPM2B_ENCRYPTED_SECRET) """ magic = int.from_bytes(credential_blob[0:4], byteorder="big") if magic != 0xBADCC0DE: raise ValueError(f"bad magic, expected 0xBADCC0DE, got 0x{magic:X}") version = int.from_bytes(credential_blob[4:8], byteorder="big") if version != 1: raise ValueError(f"bad version, expected 1, got {version}") id_object, id_object_len = TPM2B_ID_OBJECT.unmarshal(credential_blob[8:]) encrypted_secret, _ = TPM2B_ENCRYPTED_SECRET.unmarshal( credential_blob[8 + id_object_len :] ) return id_object, encrypted_secret def wrap( newparent: TPMT_PUBLIC, public: TPM2B_PUBLIC, sensitive: TPM2B_SENSITIVE, symkey: Optional[bytes] = None, symdef: Optional[TPMT_SYM_DEF_OBJECT] = None, ) -> Tuple[TPM2B_DATA, TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET]: """Wraps key under a TPM key hierarchy A key is wrapped following the Duplication protections of the TPM Architecture specification. The architecture specification is found in "Part 1: Architecture" at the following link: - https://trustedcomputinggroup.org/resource/tpm-library-specification/ At the time of this writing, spec 1.59 was most recent and it was under section 23.3, titled "Duplication". Args: newparent (TPMT_PUBLIC): The public area of the parent public (TPM2B_PUBLIC): The public area of the key sensitive (TPM2B_SENSITIVE): The sensitive area of the key symkey (bytes or None): Symmetric key for inner encryption. Defaults to None. When None and symdef is defined a key will be generated based on the key size for symdef. symdef (TPMT_SYM_DEF_OBJECT or None): Symmetric algorithm to be used for inner encryption, defaults to None. If None no inner wrapping is performed, else this should be set to aes128CFB since that is what the TPM supports. To set to aes128cfb, do: :: TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(sym=128), mode=TPMU_SYM_MODE(sym=TPM2_ALG.CFB), ) Returns: A tuple of (TPM2B_DATA, TPM2B_PRIVATE, TPM2B_ENCRYPTED_SECRET) which is the encryption key, the the wrapped duplicate and the encrypted seed. Raises: ValueError: If the public key type or symmetric algorithm are not supported """ enckeyout = TPM2B_DATA() outsymseed = TPM2B_ENCRYPTED_SECRET() sensb = sensitive.marshal() name = bytes(public.get_name()) if symdef and symdef.algorithm != TPM2_ALG.NULL: cipher, mode, bits = _symdef_to_crypt(symdef) if not symkey: klen = int(bits / 8) symkey = secrets.token_bytes(klen) halg = _get_digest(public.publicArea.nameAlg) h = hashes.Hash(halg(), backend=default_backend()) h.update(sensb) h.update(name) innerint = TPM2B_DIGEST(buffer=h.finalize()).marshal() encsens = _encrypt(cipher, mode, symkey, innerint + sensb) enckeyout.buffer = symkey else: encsens = sensb seed, outsymseed.secret = _generate_seed(newparent, b"DUPLICATE\x00") cipher, mode, bits = _symdef_to_crypt(newparent.parameters.asymDetail.symmetric) outerkey = _kdfa(newparent.nameAlg, seed, b"STORAGE", name, b"", bits) dupsens = _encrypt(cipher, mode, outerkey, encsens) halg = _get_digest(newparent.nameAlg) hmackey = _kdfa( newparent.nameAlg, seed, b"INTEGRITY", b"", b"", halg.digest_size * 8 ) outerhmac = _hmac(halg, hmackey, dupsens, name) hmacdata = TPM2B_DIGEST(buffer=outerhmac).marshal() duplicate = TPM2B_PRIVATE(buffer=hmacdata + dupsens) return (enckeyout, duplicate, outsymseed) def unwrap( newparentpub: TPMT_PUBLIC, newparentpriv: TPMT_SENSITIVE, public: TPM2B_PUBLIC, duplicate: TPM2B_PRIVATE, outsymseed: TPM2B_ENCRYPTED_SECRET, symkey: Optional[bytes] = None, symdef: Optional[TPMT_SYM_DEF_OBJECT] = None, ) -> TPM2B_SENSITIVE: """unwraps a key under a TPM key hierarchy. In essence, export key from TPM. This is the inverse function to the wrap() routine. This is usually performed by the TPM when importing objects, however, if an object is duplicated under a new parent where one has both the public and private keys, the object can be unwrapped. Args: newparentpub (TPMT_PUBLIC): The public area of the parent the key was duplicated/wrapped under. newparentpriv (TPMT_SENSITIVE): The private key of the parent the key was duplicated/wrapped under. public (TPM2B_PUBLIC): The public area of the key to be unwrapped. duplicate (TPM2B_PRIVATE): The private or wrapped key to be unwrapped. outsymseed (TPM2B_ENCRYPTED_SECRET): The output symmetric seed from a wrap or duplicate call. symkey (bytes or None): Symmetric key for inner encryption. Defaults to None. When None and symdef is defined a key will be generated based on the key size for symdef. symdef (TPMT_SYM_DEF_OBJECT or None): Symmetric algorithm to be used for inner encryption, defaults to None. If None no inner wrapping is performed, else this should be set to aes128CFB since that is what the TPM supports. To set to aes128cfb, do: :: TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(sym=128), mode=TPMU_SYM_MODE(sym=TPM2_ALG.CFB), ) Returns: A TPM2B_SENSITIVE which contains the raw key material. Raises: ValueError: If the public key type or symmetric algorithm are not supported """ halg = _get_digest(newparentpub.nameAlg) seed = _secret_to_seed(newparentpriv, newparentpub, b"DUPLICATE\x00", outsymseed) hmackey = _kdfa( newparentpub.nameAlg, seed, b"INTEGRITY", b"", b"", halg.digest_size * 8 ) buffer = bytes(duplicate) hmacdata, offset = TPM2B_DIGEST.unmarshal(buffer) outerhmac = bytes(hmacdata) dupsens = buffer[offset:] name = bytes(public.get_name()) _check_hmac(halg, hmackey, dupsens, name, outerhmac) cipher, mode, bits = _symdef_to_crypt(newparentpub.parameters.asymDetail.symmetric) outerkey = _kdfa(newparentpub.nameAlg, seed, b"STORAGE", name, b"", bits) sensb = _decrypt(cipher, mode, outerkey, dupsens) if symdef and symdef.algorithm != TPM2_ALG.NULL: if not symkey: raise RuntimeError( "Expected symkey when symdef is not None or Tsymdef.algorithm is not TPM2_ALG.NULL" ) cipher, mode, bits = _symdef_to_crypt(symdef) halg = _get_digest(public.publicArea.nameAlg) # unwrap the inner encryption which is the integrity + TPM2B_SENSITIVE innerint_and_decsens = _decrypt(cipher, mode, symkey, sensb) innerint, offset = TPM2B_DIGEST.unmarshal(innerint_and_decsens) innerint = bytes(innerint) decsensb = innerint_and_decsens[offset:] h = hashes.Hash(halg(), backend=default_backend()) h.update(decsensb) h.update(name) integrity = h.finalize() if not ct.bytes_eq(integrity, innerint): raise RuntimeError("Expected inner integrity to match") decsens = decsensb else: decsens = sensb s, l = TPM2B_SENSITIVE.unmarshal(decsens) if len(decsens) != l: raise RuntimeError( f"Expected the sensitive buffer to be size {l}, got: {len(decsens)}" ) return s class NoSuchIndex(Exception): """NV index is not defined exception Args: index (int): The NV index requested """ def __init__(self, index): self.index = index def __str__(self): return f"NV index 0x{index:08x} does not exist" class NVReadEK: """NV read callback to be used with create_ek_template Args: ectx (ESAPI): The ESAPI context for reading from NV areas auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the index being read. session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. """ def __init__( self, ectx: ESAPI, auth_handle: ESYS_TR = None, session1: ESYS_TR = ESYS_TR.PASSWORD, session2: ESYS_TR = ESYS_TR.NONE, session3: ESYS_TR = ESYS_TR.NONE, ): self._ectx = ectx self._auth_handle = auth_handle self._session1 = session1 self._session2 = session2 self._session3 = session3 self._buffer_max = 512 more = True while more: more, data = self._ectx.get_capability( TPM2_CAP.TPM_PROPERTIES, TPM2_PT.FIXED, 4096, session1=session2, session2=session3, ) props = data.data.tpmProperties for p in props: if p.property == TPM2_PT_NV.BUFFER_MAX: self._buffer_max = p.value more = False break def __call__(self, index: Union[int, TPM2_RH]) -> bytes: try: nvh = self._ectx.tr_from_tpmpublic( index, session1=self._session2, session2=self._session3 ) except TSS2_Exception as e: if e.rc == 0x18B: raise NoSuchIndex(index) else: raise e nvpub, _ = self._ectx.nv_read_public( nvh, session1=self._session2, session2=self._session3 ) nvdata = b"" left = nvpub.nvPublic.dataSize while left > 0: off = nvpub.nvPublic.dataSize - left size = self._buffer_max if left > self._buffer_max else left data = self._ectx.nv_read( nvh, size, off, auth_handle=self._auth_handle, session1=self._session1, session2=self._session2, session3=self._session3, ) nvdata = nvdata + bytes(data) left = left - len(data) return nvdata def create_ek_template( ektype: str, nv_read_cb: Callable[[Union[int, TPM2_RH]], bytes] ) -> Tuple[bytes, TPM2B_PUBLIC]: """Creates an Endorsenment Key template which when created matches the EK certificate The template is created according to TCG EK Credential Profile For TPM Family 2.0: - https://trustedcomputinggroup.org/resource/tcg-ek-credential-profile-for-tpm-family-2-0/ Args: ektype (str): The endoresment key type. nv_read_cb (Callable[Union[int, TPM2_RH]]): The callback to use for reading NV areas. Note: nv_read_cb MUST raise a NoSuchIndex exception if the NV index isn't defined. Returns: A tuple of the certificate (can be None) and the template as a TPM2B_PUBLIC instance Raises: ValueError: If ektype is unknown or if a high range certificate is requested but not found. """ template = ek_template.lookup(ektype) if template is None: raise ValueError(f"unknown EK type {ektype}") key_template = TPM2B_PUBLIC(publicArea=template.template.publicArea) if template.nonce_index is None: template_index = template.cert_index + 1 else: template_index = template.cert_index + 2 cert = None try: cert = nv_read_cb(template.cert_index) except NoSuchIndex: if ektype not in ("EK-RSA2048", "EK-ECC256"): raise ValueError(f"no certificate found for {ektype}") try: templb = nv_read_cb(template_index) tt, _ = TPMT_PUBLIC.unmarshal(templb) key_template = TPM2B_PUBLIC(publicArea=tt) except NoSuchIndex: # The TPM is not required to have these Indices, but we must try # Avoids a race on checking for NV and then reading if a delete # comes in pass nonce = None if template.nonce_index is not None: try: nonce = nv_read_cb(template.nonce_index) except NoSuchIndex: # The TPM is not required to have these Indices, but we must try # Avoids a race on checking for NV and then reading if a delete # comes in pass if nonce and key_template.publicArea.type == TPM2_ALG.RSA: key_template.publicArea.unique.rsa = nonce + ((256 - len(nonce)) * b"\x00") elif ( nonce and key_template.publicArea.type == TPM2_ALG.ECC and key_template.publicArea.parameters.eccDetail.curveID == TPM2_ECC.NIST_P256 ): key_template.publicArea.unique.ecc.x = nonce + ((32 - len(nonce)) * b"\x00") key_template.publicArea.unique.ecc.y = b"\x00" * 32 return cert, key_template def unmarshal_tools_pcr_values( buf: bytes, selections: TPML_PCR_SELECTION ) -> Tuple[int, List[bytes]]: """Unmarshal PCR digests from tpm2_quote using the values format. Args: buf (bytes): content of tpm2_quote PCR output. selections (TPML_PCR_SELECTION): The selected PCRs. Returns: A tuple of the number of bytes consumed from buf and a list of digests. """ trs = list() for sel in selections: digsize = _get_digest_size(sel.hash) pb = bytes(reversed(bytes(sel.pcrSelect))) pi = int.from_bytes(pb, "big") for i in range(0, sel.sizeofSelect * 8): if pi & (1 << i): trs.append(digsize) n = 0 digs = list() for s in trs: dig = buf[:s] n += s digs.append(dig) buf = buf[s:] return n, digs tpm2-pytss-3.0.0-rc0/test/000077500000000000000000000000001506405471500152245ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/test/TSS2_BaseTest.py000066400000000000000000000133311506405471500201240ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 import shutil import logging import os import random import socket import subprocess import sys import tempfile import time import unittest from tpm2_pytss import * class BaseTpmSimulator(object): def __init__(self): self.tpm = None self._port = None @staticmethod def ready(port): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: return s.connect_ex(("localhost", port)) == 0 def start(self): logger = logging.getLogger("DEBUG") logger.debug('Setting up simulator: "{}"'.format(self.exe)) tpm = None for _ in range(0, 20): random_port = random.randrange(2321, 65534) sim = self._start(port=random_port) for _ in range(0, 10): rc = sim.poll() if rc is not None: logger.debug(f"Simulator {self.exe} exited with {rc}") break if ( sim.poll() is None and self.ready(random_port) and self.ready(random_port + 1) ): tpm = sim break time.sleep(0.1) if tpm: self.tpm = sim self._port = random_port logger.debug(f"started {self.exe} on port {random_port}\n") break else: sim.kill() if not tpm: raise SystemError("Could not start simulator") def close(self): if self.tpm.poll() is not None: return self.tpm.terminate() try: self.tpm.wait(timeout=1) except subprocess.TimeoutExpired: self.tpm.kill() self.tpm.wait(timeout=10) def __str__(self): return self.exe class SwtpmSimulator(BaseTpmSimulator): exe = "swtpm" libname = "libtss2-tcti-swtpm.so" def __init__(self): super().__init__() self.working_dir = tempfile.TemporaryDirectory() def _start(self, port): cmd = [ "swtpm", "socket", "--tpm2", "--server", "port={}".format(port), "--ctrl", "type=tcp,port={}".format(port + 1), "--flags", "not-need-init", "--tpmstate", "dir={}".format(self.working_dir.name), ] tpm = subprocess.Popen(cmd) return tpm @property def tcti_name_conf(self): if self._port is None: return None return f"swtpm:port={self._port}" def get_tcti(self): if self._port is None: return None return TCTILdr("swtpm", f"port={self._port}") class IBMSimulator(BaseTpmSimulator): exe = "tpm_server" libname = "libtss2-tcti-mssim.so" def __init__(self): super().__init__() self.working_dir = tempfile.TemporaryDirectory() def _start(self, port): cwd = os.getcwd() os.chdir(self.working_dir.name) try: cmd = ["tpm_server", "-rm", "-port", "{}".format(port)] tpm = subprocess.Popen(cmd) return tpm finally: os.chdir(cwd) @property def tcti_name_conf(self): if self._port is None: return None return f"mssim:port={self._port}" def get_tcti(self): if self._port is None: return None return TCTILdr("mssim", f"port={self._port}") class TpmSimulator(object): SIMULATORS = [ SwtpmSimulator, IBMSimulator, ] @staticmethod def getSimulator(): for sim in TpmSimulator.SIMULATORS: exe = shutil.which(sim.exe) if not exe: print(f'Could not find executable: "{sim.exe}"', file=sys.stderr) continue if not TCTILdr.is_available(sim.libname): continue return sim() raise RuntimeError( "Expected to find a TPM 2.0 Simulator, tried {}, got None".format( TpmSimulator.SIMULATORS ) ) class TSS2_BaseTest(unittest.TestCase): def setUp(self): self.tpm = TpmSimulator.getSimulator() self.tpm.start() def tearDown(self): self.tpm.close() class TSS2_EsapiTest(TSS2_BaseTest): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.tcti = None self.ectx = None def skipIfAlgNotSupported(self, alg: TPM2_ALG): self.skipTest(f'Algorithm "{alg}" not supported by simulator') def skipIfCommandNotSupported(self, cc: TPM2_CC): self.skipTest(f'Command "{cc}" not supported by simulator') def setUp(self): super().setUp() try: # use str initializer here to test string inputs to ESAPI constructor with ESAPI(self.tpm.tcti_name_conf) as ectx: ectx.startup(TPM2_SU.CLEAR) except Exception as e: self.tpm.close() raise e self.tcti = self.tpm.get_tcti() self.ectx = ESAPI(self.tcti) # record the supported algorithms self._supported_algs = [] more = True while more: more, data = self.ectx.get_capability( TPM2_CAP.ALGS, 0, lib.TPM2_MAX_CAP_ALGS ) self._supported_algs += [x.alg for x in data.data.algorithms] self._supported_commands = [] more = True while more: more, data = self.ectx.get_capability(TPM2_CAP.ALGS, 0, lib.TPM2_MAX_CAP_CC) self._supported_commands += list(data.data.command) def tearDown(self): self.ectx.close() self.tcti.close() super().tearDown() tpm2-pytss-3.0.0-rc0/test/__init__.py000066400000000000000000000000001506405471500173230ustar00rootroot00000000000000tpm2-pytss-3.0.0-rc0/test/test_command_parser.py000066400000000000000000000326041506405471500216340ustar00rootroot00000000000000# SPDX-License-Identifier: BSD-2 import unittest from io import BytesIO from tpm2_pytss.command_parser import ( read_command, read_response, read_command_header, UINT32, read_command_sessions, TPM_ENCRYPTED_PARAMETER, tpm2_command, tpm2_response, ) from tpm2_pytss.constants import ( TPM2_ST, TPM2_CC, TPM2_SU, TPM2_RC, TPMA_SESSION, TPM2_SE, TPM2_ALG, TSS2_RC, ) from tpm2_pytss.types import ( TPM2_HANDLE, TPM2B_NONCE, TPM2B_AUTH, TPM2B_ENCRYPTED_SECRET, TPMT_SYM_DEF, TPM2B_DIGEST, TPM2B_SENSITIVE_DATA, ) from tpm2_pytss.TSS2_Exception import TSS2_Exception class CommandParserTest(unittest.TestCase): def test_startup_command(self): buf = b"" buf += TPM2_CC.Startup.marshal() buf += TPM2_SU.CLEAR.marshal() tag = TPM2_ST.NO_SESSIONS.marshal() # commandSize is size of tag, bytes for commandSize and size of parameters size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) command = read_command(fp) self.assertEqual(len(fp.getvalue()), fp.tell()) self.assertEqual(command.command_code, TPM2_CC.Startup) self.assertEqual(len(command.handles), 0) self.assertEqual(len(command.sessions), 0) self.assertEqual(len(command.parameters), 1) self.assertEqual(command.parameters, (TPM2_SU.CLEAR,)) def test_startup_response(self): buf = b"" buf += TPM2_RC.SUCCESS.marshal() tag = TPM2_ST.NO_SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) response = read_response(fp, TPM2_CC.Startup) self.assertEqual(len(fp.getvalue()), fp.tell()) self.assertEqual(response.response_code, TPM2_RC.SUCCESS) self.assertEqual(response.handle, None) self.assertEqual(len(response.sessions), 0) self.assertEqual(len(response.parameters), 0) def test_failure_response(self): buf = b"" buf += TPM2_RC.FAILURE.marshal() tag = TPM2_ST.NO_SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) response = read_response(fp, TPM2_CC.Startup) self.assertEqual(len(fp.getvalue()), fp.tell()) self.assertEqual(response.response_code, TPM2_RC.FAILURE) self.assertEqual(response.handle, None) self.assertEqual(len(response.sessions), 0) self.assertEqual(len(response.parameters), 0) def test_read_command_header(self): fp = BytesIO() fp.write(TPM2_ST.SESSIONS.marshal()) fp.write(UINT32(10).marshal()) fp.write(TPM2_CC.Startup.marshal()) fp.seek(0) print(int(10).to_bytes(4, byteorder="big")) tag, cc, left = read_command_header(fp) self.assertEqual(tag, TPM2_ST.SESSIONS) self.assertEqual(cc, TPM2_CC.Startup) self.assertEqual(left, 0) def test_read_command_sessions(self): fp = BytesIO() for i in range(0, 3): fp.write(TPM2_HANDLE(i).marshal()) fp.write(TPM2B_NONCE(32 * bytes([i])).marshal()) fp.write(TPMA_SESSION(i).marshal()) fp.write(TPM2B_AUTH(bytes([i] * 32)).marshal()) size = UINT32(len(fp.getvalue())) newfp = BytesIO() newfp.write(size.marshal()) newfp.write(fp.getvalue()) newfp.seek(0) sessions = read_command_sessions(newfp) self.assertEqual(len(sessions), 3) self.assertEqual(newfp.tell(), len(newfp.getvalue())) for i in range(0, len(sessions)): self.assertEqual(sessions[i].handle, i) self.assertEqual(sessions[i].attributes, i) self.assertEqual(sessions[i].nonce, bytes([i] * 32)) self.assertEqual(sessions[i].authorization, bytes([i] * 32)) def test_start_auth_session_command(self): buf = b"" buf += TPM2_CC.StartAuthSession.marshal() buf += TPM2_HANDLE(1).marshal() buf += TPM2_HANDLE(2).marshal() # session here session_buf = b"" session_buf += TPM2_HANDLE(1234).marshal() session_buf += TPM2B_NONCE(b"1234").marshal() session_buf += TPMA_SESSION(234).marshal() session_buf += TPM2B_AUTH(b"1234").marshal() session_size = UINT32(len(session_buf)).marshal() buf += session_size buf += session_buf # parameters here buf += TPM2B_NONCE(b"3").marshal() buf += TPM2B_ENCRYPTED_SECRET(b"4").marshal() buf += TPM2_SE.HMAC.marshal() buf += TPMT_SYM_DEF.parse("aes128cbc").marshal() buf += TPM2_ALG.SHA256.marshal() tag = TPM2_ST.SESSIONS.marshal() # commandSize is size of tag, bytes for commandSize and size of parameters size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) command = read_command(fp) self.assertEqual(command.tag, TPM2_ST.SESSIONS) self.assertEqual(len(command.handles), 2) self.assertEqual(command.handles[0], 1) self.assertEqual(command.handles[1], 2) self.assertEqual(len(command.sessions), 1) self.assertEqual(command.sessions[0].handle, TPM2_HANDLE(1234)) self.assertEqual(command.sessions[0].nonce, TPM2B_NONCE(b"1234")) self.assertEqual(command.sessions[0].attributes, TPMA_SESSION(234)) self.assertEqual(command.sessions[0].authorization, TPM2B_AUTH(b"1234")) self.assertEqual(len(command.parameters), 5) self.assertEqual(command.parameters[0], TPM2B_NONCE(b"3")) self.assertEqual(command.parameters[1], TPM2B_ENCRYPTED_SECRET(b"4")) self.assertEqual(command.parameters[2], TPM2_SE.HMAC) self.assertEqual(command.parameters[3].algorithm, TPM2_ALG.AES) self.assertEqual(command.parameters[3].mode.sym, TPM2_ALG.CBC) self.assertEqual(command.parameters[3].keyBits.sym, 128) self.assertEqual(command.parameters[4], TPM2_ALG.SHA256) def test_start_auth_session_response(self): buf = b"" buf += TPM2_RC.SUCCESS.marshal() # handle here buf += TPM2_HANDLE(1).marshal() # parameters here parameter_buf = TPM2B_NONCE(b"falafel").marshal() parameter_size = UINT32(len(parameter_buf)).marshal() buf += parameter_size + parameter_buf # sessions here session_buf = TPM2B_NONCE(b"1234").marshal() session_buf += TPMA_SESSION(123).marshal() session_buf += TPM2B_DIGEST(b"1234").marshal() session_size = UINT32(len(session_buf)).marshal() buf += session_size + session_buf tag = TPM2_ST.SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) response = read_response(fp, TPM2_CC.StartAuthSession) self.assertEqual(response.tag, TPM2_ST.SESSIONS) self.assertEqual(response.response_code, TPM2_RC.SUCCESS) self.assertEqual(response.handle, TPM2_HANDLE(1)) self.assertEqual(len(response.parameters), 1) self.assertEqual(response.parameters[0], TPM2B_NONCE(b"falafel")) self.assertEqual(len(response.sessions), 1) self.assertEqual(response.sessions[0].nonce, TPM2B_NONCE(b"1234")) self.assertEqual(response.sessions[0].attributes, TPMA_SESSION(123)) self.assertEqual(response.sessions[0].acknowledgment, TPM2B_DIGEST(b"1234")) def test_encrypt_parameter(self): buf = b"" buf += TPM2_RC.SUCCESS.marshal() parameter_buf = TPM2B_DIGEST(b"falafel").marshal() parameter_size = UINT32(len(parameter_buf)).marshal() buf += parameter_size + parameter_buf session_buf = TPM2B_NONCE(b"1234").marshal() session_buf += TPMA_SESSION.ENCRYPT.marshal() session_buf += TPM2B_DIGEST(b"1234").marshal() session_size = UINT32(len(session_buf)).marshal() buf += session_size + session_buf tag = TPM2_ST.SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) response = read_response(fp, TPM2_CC.GetRandom) self.assertEqual(response.tag, TPM2_ST.SESSIONS) self.assertEqual(response.response_code, TPM2_RC.SUCCESS) self.assertEqual(len(response.parameters), 1) self.assertIsInstance(response.parameters[0], TPM_ENCRYPTED_PARAMETER) self.assertEqual(response.parameters[0].underlying_type, TPM2B_DIGEST) self.assertEqual(response.parameters[0], b"falafel") self.assertEqual(len(response.sessions), 1) self.assertEqual(response.sessions[0].nonce, TPM2B_NONCE(b"1234")) self.assertEqual(response.sessions[0].attributes, TPMA_SESSION.ENCRYPT) self.assertEqual(response.sessions[0].acknowledgment, TPM2B_DIGEST(b"1234")) def test_decrypt_parameter(self): buf = b"" buf += TPM2_CC.StirRandom.marshal() session_buf = b"" session_buf += TPM2_HANDLE(1234).marshal() session_buf += TPM2B_NONCE(b"1234").marshal() session_buf += TPMA_SESSION.DECRYPT.marshal() session_buf += TPM2B_AUTH(b"1234").marshal() session_size = UINT32(len(session_buf)).marshal() buf += session_size + session_buf buf += TPM2B_SENSITIVE_DATA(b"falafel").marshal() tag = TPM2_ST.SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) command = read_command(fp) self.assertEqual(command.tag, TPM2_ST.SESSIONS) self.assertEqual(len(command.sessions), 1) self.assertEqual(command.sessions[0].handle, TPM2_HANDLE(1234)) self.assertEqual(command.sessions[0].nonce, TPM2B_NONCE(b"1234")) self.assertEqual(command.sessions[0].attributes, TPMA_SESSION.DECRYPT) self.assertEqual(command.sessions[0].authorization, TPM2B_AUTH(b"1234")) self.assertIsInstance(command.parameters[0], TPM_ENCRYPTED_PARAMETER) self.assertEqual(command.parameters[0].underlying_type, TPM2B_SENSITIVE_DATA) self.assertEqual(command.parameters[0], b"falafel") def test_command_bad_tag(self): buf = b"" buf += TPM2_CC.Startup.marshal() buf += TPM2_SU.CLEAR.marshal() tag = TPM2_ST.NULL.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) with self.assertRaises(TSS2_Exception) as e: read_command(fp) self.assertEqual(e.exception.rc, TPM2_RC.BAD_TAG) def test_response_bad_tag(self): buf = b"" buf += TPM2_RC.SUCCESS.marshal() tag = TPM2_ST.ATTEST_NV.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) with self.assertRaises(TSS2_Exception) as e: read_response(fp, TPM2_CC.Startup) self.assertEqual(e.exception.rc, TPM2_RC.BAD_TAG) def test_tpm_encrypted_parameter(self): p = TPM_ENCRYPTED_PARAMETER(TPM2B_DIGEST, b"falafel") self.assertEqual(bytes(p), b"falafel") marshaled = p.marshal() self.assertEqual(marshaled, b"\x00\x07falafel") self.assertNotEqual(p, "falafel") def test_missing_commands(self): with self.assertRaises(TSS2_Exception) as e: tpm2_command.lookup_command_class(TPM2_CC.LAST + 1) self.assertEqual(e.exception.rc, TSS2_RC.BASE_RC_NOT_IMPLEMENTED) with self.assertRaises(TSS2_Exception) as e: tpm2_response.lookup_response_class(TPM2_CC.LAST + 1) self.assertEqual(e.exception.rc, TSS2_RC.BASE_RC_NOT_IMPLEMENTED) def test_without_encrypted_parameter(self): buf = b"" buf += TPM2_RC.SUCCESS.marshal() parameter_buf = TPM2B_DIGEST(b"falafel").marshal() parameter_size = UINT32(len(parameter_buf)).marshal() buf += parameter_size + parameter_buf session_buf = TPM2B_NONCE(b"1234").marshal() session_buf += TPMA_SESSION(0).marshal() session_buf += TPM2B_DIGEST(b"1234").marshal() session_size = UINT32(len(session_buf)).marshal() buf += session_size + session_buf tag = TPM2_ST.SESSIONS.marshal() size = len(tag) + 4 + len(buf) size_bytes = size.to_bytes(4, byteorder="big") fp = BytesIO() fp.write(tag) fp.write(size_bytes) fp.write(buf) fp.seek(0) response = read_response(fp, TPM2_CC.GetRandom) self.assertIsInstance(response.parameters[0], TPM2B_DIGEST) tpm2-pytss-3.0.0-rc0/test/test_crypto.py000066400000000000000000001110721506405471500201570ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest from tpm2_pytss import * from tpm2_pytss.internal import * from .TSS2_BaseTest import TSS2_EsapiTest from base64 import b64decode from hashlib import sha256, sha384 from cryptography.hazmat.primitives.serialization import load_pem_public_key from cryptography.exceptions import UnsupportedAlgorithm rsa_private_key = b""" -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAxU5SokcbkKjsgBGsQhBF70LM2yudAGPUiHbLObvNJSwDcN8L TNN1Cg1+Q4VWb/jkEFEUMCHce6Rqq3xu+kTsj+J1BVfBIkxcNr7TdDCsgNiA4BX+ kGo4W0Z5y9AGiJNb2jjim+BoYwY67fGNKv2FE3BFdWLSoQcbdDAjStLw3yJ+nhz4 Op6dJRTyu8XWxYJwXziIAHBcNFAM7ipT9Yypv5+wZ8FyQizzUj321DruGzOPPKdy ISbRYGeyq3s8oSlui+2zIiEOb428+OWzttgwz2jfwJ8NQGXTRp1Iw/L/xottZPkA Yobff75SOv7or+sHlMpkLjtuftEhdpWnPIjXXwIDAQABAoIBAHFplvgulXqujtsC zZhf0EM6i5SD2khKGfWjCygRelcemI+9tbogZksz/FsFfuz4DOgQIuGT5S+xD5uo +AWlrrD6Q7ehfKOhbvQM9nD4NYAOcu3b1qreU6yrswDjf43r3kVuo1tkP7yD7UWu ri2C8oZ854AVIOtssWw062RsIgavw5yYG7igUVehOxQPRfP6YezYI8qTYwUy1T2i SQMcRzT5Q8KZnfPzJFse255X55Zf5reKDEruFtIQtHZl+FeL4wjb2xSQfIXV4KFa zRGVRuNyBKLVG8TVwLZdmL4zRWG3gHoFcVCCaIOunhHbN8lqjDj35XOKqt7BBzNx UrOrX4kCgYEA66V3YzEc0qTdqlTza2Il/eM/XoQStitQLLykZ/+yPWAgDr0XXAtg atVctFU61sejXsd8zBxuBk2KrZ2dbrnzxszytiA2+pFzsY8g4XwA5+7Zs8yRrMAI S6jNuuOBjseK8PfuEaO8wNbJGYxoEJtOvBl1M/U5HreaJsahnnuFmA0CgYEA1lkW D+Xj/SEGZY2aPVGKYvtWYzzHBm2JKLh2GpG5RZheTqwFXo6XeG2G63ZkupH/pQOg QXMIk4Lb/y6XapulmnLXprTQRFv+6b7sLA8u5DAAWmjbrRNU+iEuxkaDnaoHjxxK SxCcg4jQPbNmC/YRh5DOaeNJm+19HGd+gj2HhhsCgYBdoyCvv8JOScjzeFJJ53Rl ULnLmvu8e7WeMU+7K7XuAZZ7hNQVdUfY6/OsjPmWgzn93ZNPoDRwOLvUhX8bkrS1 2JbRnDd8lfO9KLzOHPJXN2g2tCFm3d/uAKPPkbvXup8RZdOqGsBUeITsrAhmIPDG ee9CuDz8YcTVh7SNP1Q0uQKBgF88CZ9apudKiwsH1SW1WuULgqBo2oyykiQzgNXh NQ4E2rHdoC0Y8ZeiIjXvzmVOhOUOLV+m+oJ/u7svOjs1mGh86e+5mmck8KduGoSg 4lakNSP2PtQxKKpRn/ScU9HzP5SIH0ImyUNvwAYJ9ScPV06COhO11nifFd1O5lh7 egFNAoGAUb6hqU4FE8DO8raO+dwTZBZqrlOldF7/L8aK2Xp98jkwtUIU0WLlo3AX BWUSCMWPt/jlmVdZPb8jFkGTlkrpy8dSlZQ1oja8nlaxjXuSy57dYRVkDUGLfvsJ 1fG6ahkXCMzRx03YPkp2Yi/ZyRIdvlwKugQNPxx+qSWCauBvUY4= -----END RSA PRIVATE KEY----- """ rsa_public_key = b"""-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU5SokcbkKjsgBGsQhBF 70LM2yudAGPUiHbLObvNJSwDcN8LTNN1Cg1+Q4VWb/jkEFEUMCHce6Rqq3xu+kTs j+J1BVfBIkxcNr7TdDCsgNiA4BX+kGo4W0Z5y9AGiJNb2jjim+BoYwY67fGNKv2F E3BFdWLSoQcbdDAjStLw3yJ+nhz4Op6dJRTyu8XWxYJwXziIAHBcNFAM7ipT9Yyp v5+wZ8FyQizzUj321DruGzOPPKdyISbRYGeyq3s8oSlui+2zIiEOb428+OWzttgw z2jfwJ8NQGXTRp1Iw/L/xottZPkAYobff75SOv7or+sHlMpkLjtuftEhdpWnPIjX XwIDAQAB -----END PUBLIC KEY----- """ rsa_public_key_bytes = b'\xc5NR\xa2G\x1b\x90\xa8\xec\x80\x11\xacB\x10E\xefB\xcc\xdb+\x9d\x00c\xd4\x88v\xcb9\xbb\xcd%,\x03p\xdf\x0bL\xd3u\n\r~C\x85Vo\xf8\xe4\x10Q\x140!\xdc{\xa4j\xab|n\xfaD\xec\x8f\xe2u\x05W\xc1"L\\6\xbe\xd3t0\xac\x80\xd8\x80\xe0\x15\xfe\x90j8[Fy\xcb\xd0\x06\x88\x93[\xda8\xe2\x9b\xe0hc\x06:\xed\xf1\x8d*\xfd\x85\x13pEub\xd2\xa1\x07\x1bt0#J\xd2\xf0\xdf"~\x9e\x1c\xf8:\x9e\x9d%\x14\xf2\xbb\xc5\xd6\xc5\x82p_8\x88\x00p\\4P\x0c\xee*S\xf5\x8c\xa9\xbf\x9f\xb0g\xc1rB,\xf3R=\xf6\xd4:\xee\x1b3\x8f<\xa7r!&\xd1`g\xb2\xab{<\xa1)n\x8b\xed\xb3"!\x0eo\x8d\xbc\xf8\xe5\xb3\xb6\xd80\xcfh\xdf\xc0\x9f\r@e\xd3F\x9dH\xc3\xf2\xff\xc6\x8bmd\xf9\x00b\x86\xdf\x7f\xbeR:\xfe\xe8\xaf\xeb\x07\x94\xcad.;n~\xd1!v\x95\xa7<\x88\xd7_' rsa_private_key_bytes = b"\xeb\xa5wc1\x1c\xd2\xa4\xdd\xaaT\xf3kb%\xfd\xe3?^\x84\x12\xb6+P,\xbc\xa4g\xff\xb2=` \x0e\xbd\x17\\\x0b`j\xd5\\\xb4U:\xd6\xc7\xa3^\xc7|\xcc\x1cn\x06M\x8a\xad\x9d\x9dn\xb9\xf3\xc6\xcc\xf2\xb6 6\xfa\x91s\xb1\x8f \xe1|\x00\xe7\xee\xd9\xb3\xcc\x91\xac\xc0\x08K\xa8\xcd\xba\xe3\x81\x8e\xc7\x8a\xf0\xf7\xee\x11\xa3\xbc\xc0\xd6\xc9\x19\x8ch\x10\x9bN\xbc\x19u3\xf59\x1e\xb7\x9a&\xc6\xa1\x9e{\x85\x98\r" ecc_private_key = b""" -----BEGIN EC PRIVATE KEY----- MHcCAQEEIMJI9ujmlT/qftbXWlMwOSpkxiWLAbyIMWEFPOqTbXYMoAoGCCqGSM49 AwEHoUQDQgAEgO/tHxp/YOuP4wAV3w66C8JNiSHOKSAYtlNKSN4ZDI//wn0f7zBv Uc7FqaRPA9LL6k6C1YfdOi/yvTB7Y4Tgaw== -----END EC PRIVATE KEY----- """ ecc_public_key = b"""-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgO/tHxp/YOuP4wAV3w66C8JNiSHO KSAYtlNKSN4ZDI//wn0f7zBvUc7FqaRPA9LL6k6C1YfdOi/yvTB7Y4Tgaw== -----END PUBLIC KEY----- """ ecc_public_key_bytes = b"\x80\xef\xed\x1f\x1a\x7f`\xeb\x8f\xe3\x00\x15\xdf\x0e\xba\x0b\xc2M\x89!\xce) \x18\xb6SJH\xde\x19\x0c\x8f\xff\xc2}\x1f\xef0oQ\xce\xc5\xa9\xa4O\x03\xd2\xcb\xeaN\x82\xd5\x87\xdd:/\xf2\xbd0{c\x84\xe0k" ecc_private_key_bytes = b"\xc2H\xf6\xe8\xe6\x95?\xea~\xd6\xd7ZS09*d\xc6%\x8b\x01\xbc\x881a\x05<\xea\x93mv\x0c" rsa_cert = b""" -----BEGIN CERTIFICATE----- MIIFqzCCA5OgAwIBAgIBAzANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJERTEh MB8GA1UECgwYSW5maW5lb24gVGVjaG5vbG9naWVzIEFHMRswGQYDVQQLDBJPUFRJ R0EoVE0pIERldmljZXMxKDAmBgNVBAMMH0luZmluZW9uIE9QVElHQShUTSkgUlNB IFJvb3QgQ0EwHhcNMTMwNzI2MDAwMDAwWhcNNDMwNzI1MjM1OTU5WjB3MQswCQYD VQQGEwJERTEhMB8GA1UECgwYSW5maW5lb24gVGVjaG5vbG9naWVzIEFHMRswGQYD VQQLDBJPUFRJR0EoVE0pIERldmljZXMxKDAmBgNVBAMMH0luZmluZW9uIE9QVElH QShUTSkgUlNBIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC7E+gc0B5T7awzux66zMMZMTtCkPqGv6a3NVx73ICg2DSwnipFwBiUl9soEodn 25SVVN7pqmvKA2gMTR5QexuYS9PPerfRZrBY00xyFx84V+mIRPg4YqUMLtZBcAwr R3GO6cffHp20SBH5ITpuqKciwb0v5ueLdtZHYRPq1+jgy58IFY/vACyF/ccWZxUS JRNSe4ruwBgI7NMWicxiiWQmz1fE3e0mUGQ1tu4M6MpZPxTZxWzN0mMz9noj1oIT ZUnq/drN54LHzX45l+2b14f5FkvtcXxJ7OCkI7lmWIt8s5fE4HhixEgsR2RX5hzl 8XiHiS7uD3pQhBYSBN5IBbVWREex1IUat5eAOb9AXjnZ7ivxJKiY/BkOmrNgN8k2 7vOS4P81ix1GnXsjyHJ6mOtWRC9UHfvJcvM3U9tuU+3dRfib03NGxSPnKteL4SP1 bdHfiGjV3LIxzFHOfdjM2cvFJ6jXg5hwXCFSdsQm5e2BfT3dWDBSfR4h3Prpkl6d cAyb3nNtMK3HR5yl6QBuJybw8afHT3KRbwvOHOCR0ZVJTszclEPcM3NQdwFlhqLS ghIflaKSPv9yHTKeg2AB5q9JSG2nwSTrjDKRab225+zJ0yylH5NwxIBLaVHDyAEu 81af+wnm99oqgvJuDKSQGyLf6sCeuy81wQYO46yNa+xJwQIDAQABo0IwQDAdBgNV HQ4EFgQU3LtWq/EY/KaadREQZYQSntVBkrkwDgYDVR0PAQH/BAQDAgAGMA8GA1Ud EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGHTBUx3ETIXYJsaAgb2pyyN UltVL2bKzGMVSsnTCrXUU8hKrDQh3jNIMrS0d6dU/fGaGJvehxmmJfjaN/IFWA4M BdZEnpAe2fJEP8vbLa/QHVfsAVuotLD6QWAqeaC2txpxkerveoV2JAwj1jrprT4y rkS8SxZuKS05rYdlG30GjOKTq81amQtGf2NlNiM0lBB/SKTt0Uv5TK0jIWbz2WoZ gGut7mF0md1rHRauWRcoHQdxWSQTCTtgoQzeBj4IS6N3QxQBKV9LL9UWm+CMIT7Y np8bSJ8oW4UdpSuYWe1ZwSjZyzDiSzpuc4gTS6aHfMmEfoVwC8HN03/HD6B1Lwo2 DvEaqAxkya9IYWrDqkMrEErJO6cqx/vfIcfY/8JYmUJGTmvVlaODJTwYwov/2rjr la5gR+xrTM7dq8bZimSQTO8h6cdL6u+3c8mGriCQkNZIZEac/Gdn+KwydaOZIcnf Rdp3SalxsSp6cWwJGE4wpYKB2ClM2QF3yNQoTGNwMlpsxnU72ihDi/RxyaRTz9OR pubNq8Wuq7jQUs5U00ryrMCZog1cxLzyfZwwCYh6O2CmbvMoydHNy5CU3ygxaLWv JpgZVHN103npVMR3mLNa3QE+5MFlBlP3Mmystu8iVAKJas39VO5y5jad4dRLkwtM 6sJa8iBpdRjZrBp5sJBI -----END CERTIFICATE----- """ ecc_cert = b""" -----BEGIN CERTIFICATE----- MIICWzCCAeKgAwIBAgIBBDAKBggqhkjOPQQDAzB3MQswCQYDVQQGEwJERTEhMB8G A1UECgwYSW5maW5lb24gVGVjaG5vbG9naWVzIEFHMRswGQYDVQQLDBJPUFRJR0Eo VE0pIERldmljZXMxKDAmBgNVBAMMH0luZmluZW9uIE9QVElHQShUTSkgRUNDIFJv b3QgQ0EwHhcNMTMwNzI2MDAwMDAwWhcNNDMwNzI1MjM1OTU5WjB3MQswCQYDVQQG EwJERTEhMB8GA1UECgwYSW5maW5lb24gVGVjaG5vbG9naWVzIEFHMRswGQYDVQQL DBJPUFRJR0EoVE0pIERldmljZXMxKDAmBgNVBAMMH0luZmluZW9uIE9QVElHQShU TSkgRUNDIFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQm1HxLVgvAu1q2 GM+ymTz12zdTEu0JBVG9CdsVEJv/pE7pSWOlsG3YwU792YAvjSy7zL+WtDK40KGe Om8bSWt46QJ00MQUkYxz6YqXbb14BBr06hWD6u6IMBupNkPd9pKjQjBAMB0GA1Ud DgQWBBS0GIXISkrFEnryQDnexPWLHn5K0TAOBgNVHQ8BAf8EBAMCAAYwDwYDVR0T AQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjA6QZcV8DjjbPuKjKDZQmTRywZk MAn8wE6kuW3EouVvBt+/2O+szxMe4vxj8R6TDCYCMG7c9ov86ll/jDlJb/q0L4G+ +O3Bdel9P5+cOgzIGANkOPEzBQM3VfJegfnriT/kaA== -----END CERTIFICATE----- """ ssh_ecc_public = b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOhMD+1HRoFoPTyGrldrZf0iZh2HjMzpm8oNioTIVDDpxHVb1+fW31P+iz8aUAdO25Nr01aWfPPrF869Zd5d9Yw=" ssh_ecc_private = b""" -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQToTA/tR0aBaD08hq5Xa2X9ImYdh4zM 6ZvKDYqEyFQw6cR1W9fn1t9T/os/GlAHTtuTa9NWlnzz6xfOvWXeXfWMAAAAqE5gSiZOYE omAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOhMD+1HRoFoPTyG rldrZf0iZh2HjMzpm8oNioTIVDDpxHVb1+fW31P+iz8aUAdO25Nr01aWfPPrF869Zd5d9Y wAAAAhAMBHdu575J/t4f/y9jqaPawioLJTCqQcd2MWdLcAbhPlAAAACndob0BzdmFsYW4B AgMEBQ== -----END OPENSSH PRIVATE KEY----- """ rsa_three_exponent = b""" -----BEGIN PUBLIC KEY----- MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAlxQ6vHpzuhFpXRkI0Xyg nK1OR94kJlU+8On+JM1CjLpMORSAUJ+/SazftAUahmgjJ/7cnXN4P4SIDzEHGll0 wvrJS9d7ladGHYP09kjXyZex3NXUahqmn6kFAHhbdHHIDsMr1cO021gCUDKuJV3X 3T2rqtc+0ZbFhg/Rp70WSAD84kaYP5jaBDNvK3t7DhGvMvkXY6SmFt045yHyDGfg YE1bW8Ji+NxLIXJ/PmUBOFUaV6//32ywiDM6Sri89k/AV/gFRcTVHKgVrvkkFo9M 62I2eXz60GrWEs7HHDH4JrsUSDzwvQkYflnMOtbDRkhWs8JOI9/Su/T6rcYRbgiz XQIBAw== -----END PUBLIC KEY----- """ ecc_bad_curve = b""" -----BEGIN PUBLIC KEY----- MEAwEAYHKoZIzj0CAQYFK4EEAA8DLAAEAH/ZAcztuiVJUsbprwXEyeHDzNscA7bn wF24s98qYmAu3ENjz6XPl/xv -----END PUBLIC KEY----- """ dsa_private_key = b""" -----BEGIN DSA PRIVATE KEY----- MIIBuwIBAAKBgQDWcNPSloGagE3WyinH+/vhAT0rxwyoaI7EmQguggD8z/Dq477C F1kIWNS53jyM3e6K7iIDGqrg/StsHjM1bvp0kzAJuZqOrAmP8tqns1CbAVn9WMIc aHw/fVvpZ4XbZ1TmvZNXtNwYil77Q1GDtw9zdqRWeyjbY10dsHjByxXUeQIVAKcD S5p35NOrm1XX3B0ySCLVPsajAoGASLqlBGsJ4ANh5X/rxdMHMAVrDzH/XprpvqLC qVNOrBQvoE977aNQWuZ8J+1hjGhV7BDjLoULRg6J+rH3c6YcY27ALmB1uMalrjU1 1c4XOxFQ28eFqBpVyXj1HON3Wv4IJoBxLp5+R5HfAX+N9+b6KS2ltwyozK4aBzGN kgWTlfcCgYEAoSeNK9IG0FRNxBJAOK3wMSQlDCqUB3ZdMYw9h8AUM19E1VWHbs6v 64UzSjiUBmpttqPCQVmgJKRRrPbikVHOzMC8asEH0uIjxyxicfkhpOoSinD/9/0A fhqkWGROM1oBkrLWlD2DNwVglcwsZlRacrXg5ubEQ18+gn3+xvLrQ0ACFEXN6I9P 0SKQIMmGu3B02XkbI5dH -----END DSA PRIVATE KEY----- """ dsa_public_key = b""" -----BEGIN PUBLIC KEY----- MIIBtzCCASsGByqGSM44BAEwggEeAoGBANZw09KWgZqATdbKKcf7++EBPSvHDKho jsSZCC6CAPzP8OrjvsIXWQhY1LnePIzd7oruIgMaquD9K2weMzVu+nSTMAm5mo6s CY/y2qezUJsBWf1YwhxofD99W+lnhdtnVOa9k1e03BiKXvtDUYO3D3N2pFZ7KNtj XR2weMHLFdR5AhUApwNLmnfk06ubVdfcHTJIItU+xqMCgYBIuqUEawngA2Hlf+vF 0wcwBWsPMf9emum+osKpU06sFC+gT3vto1Ba5nwn7WGMaFXsEOMuhQtGDon6sfdz phxjbsAuYHW4xqWuNTXVzhc7EVDbx4WoGlXJePUc43da/ggmgHEunn5Hkd8Bf433 5vopLaW3DKjMrhoHMY2SBZOV9wOBhQACgYEAoSeNK9IG0FRNxBJAOK3wMSQlDCqU B3ZdMYw9h8AUM19E1VWHbs6v64UzSjiUBmpttqPCQVmgJKRRrPbikVHOzMC8asEH 0uIjxyxicfkhpOoSinD/9/0AfhqkWGROM1oBkrLWlD2DNwVglcwsZlRacrXg5ubE Q18+gn3+xvLrQ0A= -----END PUBLIC KEY----- """ ecc_encrypted_key = b""" -----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,3E4AA4A32C548CBB67F0D619538BE10B kjWZRRxDAcydDyuX3p3ZIaPqa2QtI7hA0neoLbSrbdJ0mNjN63epDJYAvQpIxYv9 QuvaxyX7VW4guemvj/ZvHu3HuKr0TlvBqVtsGqIJbi3eCFvmll//qo1AG0mDAopL I8/rxsxXVofKhAfCeJ4gP6LOlr6uLQKdf0wYxzcYEZI= -----END EC PRIVATE KEY----- """ class CryptoTest(TSS2_EsapiTest): def setUp(self): super().setUp() self._has_sect163r2 = True try: load_pem_public_key(ecc_bad_curve) except (ValueError, UnsupportedAlgorithm): self._has_sect163r2 = False def test_public_from_pem_rsa(self): pub = TPM2B_PUBLIC() crypto._public_from_encoding(rsa_public_key, pub.publicArea) self.assertEqual(pub.publicArea.type, TPM2_ALG.RSA) self.assertEqual(pub.publicArea.parameters.rsaDetail.keyBits, 2048) self.assertEqual(pub.publicArea.parameters.rsaDetail.exponent, 0) self.assertEqual(bytes(pub.publicArea.unique.rsa.buffer), rsa_public_key_bytes) def test_private_from_pem_rsa(self): priv = TPM2B_SENSITIVE() crypto._private_from_encoding(rsa_private_key, priv.sensitiveArea) self.assertEqual(priv.sensitiveArea.sensitiveType, TPM2_ALG.RSA) self.assertEqual( bytes(priv.sensitiveArea.sensitive.rsa.buffer), rsa_private_key_bytes ) def test_loadexternal_rsa(self): pub = TPM2B_PUBLIC.from_pem(rsa_public_key) self.assertEqual(pub.publicArea.nameAlg, TPM2_ALG.SHA256) self.assertEqual( pub.publicArea.objectAttributes, (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH), ) self.assertEqual( pub.publicArea.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL ) self.assertEqual( pub.publicArea.parameters.rsaDetail.scheme.scheme, TPM2_ALG.NULL ) priv = TPM2B_SENSITIVE.from_pem(rsa_private_key) # test without Hierarchy handle = self.ectx.load_external(pub, priv) self.assertNotEqual(handle, 0) # negative test with self.assertRaises(TypeError): self.ectx.load_external(pub, TPM2B_PUBLIC()) with self.assertRaises(TypeError): self.ectx.load_external(priv, priv) with self.assertRaises(ValueError): self.ectx.load_external(pub, priv, 7467644) with self.assertRaises(TypeError): self.ectx.load_external(pub, priv, object) with self.assertRaises(TypeError): self.ectx.load_external(pub, priv, session1=76.5) with self.assertRaises(TypeError): self.ectx.load_external(pub, priv, session2=object()) with self.assertRaises(TypeError): self.ectx.load_external(pub, priv, session3=TPM2B_PUBLIC()) def test_public_from_pem_ecc(self): pub = TPM2B_PUBLIC() crypto._public_from_encoding(ecc_public_key, pub.publicArea) self.assertEqual(pub.publicArea.type, TPM2_ALG.ECC) self.assertEqual( pub.publicArea.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256 ) self.assertEqual( bytes(pub.publicArea.unique.ecc.x.buffer), ecc_public_key_bytes[0:32] ) self.assertEqual( bytes(pub.publicArea.unique.ecc.y.buffer), ecc_public_key_bytes[32:64] ) def test_private_from_pem_ecc(self): priv = types.TPM2B_SENSITIVE() crypto._private_from_encoding(ecc_private_key, priv.sensitiveArea) self.assertEqual(priv.sensitiveArea.sensitiveType, TPM2_ALG.ECC) self.assertEqual( bytes(priv.sensitiveArea.sensitive.ecc.buffer), ecc_private_key_bytes ) def test_loadexternal_ecc(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) self.assertEqual(pub.publicArea.nameAlg, TPM2_ALG.SHA256) self.assertEqual( pub.publicArea.objectAttributes, (TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH), ) self.assertEqual( pub.publicArea.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.NULL ) self.assertEqual( pub.publicArea.parameters.eccDetail.scheme.scheme, TPM2_ALG.NULL ) self.assertEqual(pub.publicArea.parameters.eccDetail.kdf.scheme, TPM2_ALG.NULL) priv = TPM2B_SENSITIVE.from_pem(ecc_private_key) self.ectx.load_external(pub, priv, ESYS_TR.RH_NULL) def test_loadexternal_public_rsa(self): pub = TPM2B_PUBLIC.from_pem(rsa_public_key) self.ectx.load_external(pub) def test_public_to_pem_rsa(self): pub = TPM2B_PUBLIC.from_pem(rsa_public_key) pem = crypto._public_to_pem(pub.publicArea) self.assertEqual(pem, rsa_public_key) def test_public_to_pem_ecc(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) pem = crypto._public_to_pem(pub.publicArea) self.assertEqual(pem, ecc_public_key) def test_public_to_pem_bad_key(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) pub.publicArea.type = TPM2_ALG.NULL with self.assertRaises(ValueError) as e: crypto._public_to_pem(pub.publicArea) self.assertEqual(str(e.exception), f"unsupported key type: {TPM2_ALG.NULL}") def test_topem_rsa(self): pub = TPM2B_PUBLIC.from_pem(rsa_public_key) pem = pub.to_pem() self.assertEqual(pem, rsa_public_key) def test_topem_ecc(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) pem = pub.to_pem() self.assertEqual(pem, ecc_public_key) def test_public_getname(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) priv = TPM2B_SENSITIVE.from_pem(ecc_private_key) handle = self.ectx.load_external(pub, priv) ename = self.ectx.tr_get_name(handle) oname = pub.get_name() self.assertEqual(ename.name, oname.name) pub.publicArea.nameAlg = TPM2_ALG.ERROR with self.assertRaises(ValueError) as e: pub.get_name() self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.ERROR}" ) def test_nv_getname(self): nv = TPMS_NV_PUBLIC( nvIndex=0x1000000, nameAlg=TPM2_ALG.SHA1, attributes=TPMA_NV.AUTHREAD | TPMA_NV.AUTHWRITE, dataSize=123, ) oname = nv.get_name() nv2b = TPM2B_NV_PUBLIC(nvPublic=nv) handle = self.ectx.nv_define_space(b"1234", nv2b) ename = self.ectx.tr_get_name(handle) self.assertEqual(ename.name, oname.name) def test_public_from_pem_rsa_pem_cert(self): pub = TPMT_PUBLIC() crypto._public_from_encoding(rsa_cert, pub) def test_public_from_pem_rsa_der_cert(self): sl = rsa_cert.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) pub = TPMT_PUBLIC() crypto._public_from_encoding(der, pub) def test_public_from_pem_ecc_pem_cert(self): pub = TPMT_PUBLIC() crypto._public_from_encoding(ecc_cert, pub) def test_public_from_pem_ecc_der_cert(self): sl = ecc_cert.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) pub = TPMT_PUBLIC() crypto._public_from_encoding(der, pub) def test_public_from_pem_rsa_der(self): sl = rsa_public_key.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) pub = TPMT_PUBLIC() crypto._public_from_encoding(der, pub) def test_public_from_pem_ecc_der(self): sl = ecc_public_key.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) pub = TPMT_PUBLIC() crypto._public_from_encoding(der, pub) def test_public_from_pem_bad_der(self): der = b"" * 1024 pub = TPMT_PUBLIC() with self.assertRaises(ValueError) as e: crypto._public_from_encoding(der, pub) self.assertEqual(str(e.exception), "Unsupported key format") def test_private_from_pem_rsa_der(self): sl = rsa_private_key.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) sens = TPM2B_SENSITIVE() crypto._private_from_encoding(der, sens.sensitiveArea) def test_private_from_pem_ecc_der(self): sl = ecc_private_key.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) sens = TPM2B_SENSITIVE() crypto._private_from_encoding(der, sens.sensitiveArea) def test_private_from_pem_bad_der(self): der = b"" * 1024 pub = TPM2B_PUBLIC() with self.assertRaises(ValueError) as e: crypto._private_from_encoding(der, pub) self.assertEqual(str(e.exception), "Unsupported key format") def test_kdfa(self): ekey = b"a\xe2\xb8{@f\xc0\x94\xa3Pt\x08\xf5\xaf\x01[\xce\x85t\x843\xf8\xb3\x03%q\xe5\x84x\xdc`\x81E \xf5\xa9\xe8\x9f\xc8\xc9\x96U\xbe\x1b\x07\xd9\x8f\x97*~\xf7\x9bX\x99\xbe\x86\xe7\x10g$\x9cUQT\x97\x00\x9a\x97\xfd\xf0]\xec.\xedw\xb4\xf5\x8a/)\x18D\x13W6?`{!f\xf5\xa7\xd9>E\xf7\xd66\x11j\x8aZ\x06\xe1\nJJ\x99\xb4\x9e\x15\xea\xed\xb0\x98i\xcd\xa5cI4Pq\xae\xe8\x0c6\xbae\xb1t\xe1ku\x94\x06,\xe6'\x1b\xedn\xf2T\xf7\xbd\xb4\xfeu\x7f\xacD\x9e\xcb[rHN\xf4g1C\xb3\xd9ML\xd2:\x06\xea\xb1I\x98\xa7\xe2\xa0\x99\x8b\x82\xb9n\xad\xb6\x1cZ\xa8>!\xb9\x81\xf9\x03w\x88F\n\x19\xb1^\xd8\x801\xd6\x9dF\xf3\xc3\x05\x91\x92L\xc1\xd0\xaei;\x18n\xad=v'e\xa7\xcc6\xa7\xa2\"PB\x9f\xfb\xad\xebA\x00\x8d\xee\x99\x10\xafA\xc3\xc9\xe6\xd7\xaaIe\xdf/:\xf3C{" key = crypto._kdfa( TPM2_ALG.SHA256, b"key data", b"label data", b"contextU data", b"contextV data", 2048, ) self.assertEqual(key, ekey) with self.assertRaises(ValueError) as e: crypto._kdfa( TPM2_ALG.SHA256, b"key data", b"label data", b"contextU data", b"contextV data", 123, ) self.assertEqual(str(e.exception), "bad key length 123, not a multiple of 8") with self.assertRaises(ValueError) as e: crypto._kdfa( TPM2_ALG.LAST + 1, b"key data", b"label data", b"contextU data", b"contextV data", 2048, ) self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.LAST + 1}" ) def test_kdfe(self): ekey = b"@|\x8bb\x92\x1c\x85\x06~\xc5d!\x14^\xb44\x01\xaf\xa2\xac(\xb98T3\x91m\x83L\xa9\xdcX" key = crypto.kdfe( TPM2_ALG.SHA256, b"z data", b"use data", b"partyuinfo data", b"partyvinfo data", 256, ) self.assertEqual(key, ekey) with self.assertRaises(ValueError) as e: crypto.kdfe( TPM2_ALG.SHA256, b"z data", b"use data", b"partyuinfo data", b"partyvinfo data", 123, ) self.assertEqual(str(e.exception), "bad key length 123, not a multiple of 8") with self.assertRaises(ValueError) as e: crypto.kdfe( TPM2_ALG.LAST + 1, b"z data", b"use data", b"partyuinfo data", b"partyvinfo data", 256, ) self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.LAST + 1}" ) def test_get_alg(self): alg = crypto._get_alg(TPM2_ALG.AES) self.assertEqual(alg, crypto.AES) nalg = crypto._get_alg(TPM2_ALG.LAST + 1) self.assertEqual(nalg, None) def test_symdef_to_crypt(self): symdef = TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.AES) symdef.mode.sym = TPM2_ALG.CFB symdef.keyBits.sym = 128 (alg, mode, bits) = crypto._symdef_to_crypt(symdef) self.assertEqual(alg, crypto.AES) self.assertEqual(mode, crypto.modes.CFB) self.assertEqual(bits, 128) symdef.mode.sym = TPM2_ALG.LAST + 1 with self.assertRaises(ValueError) as e: crypto._symdef_to_crypt(symdef) self.assertEqual( str(e.exception), f"unsupported symmetric mode {TPM2_ALG.LAST + 1}" ) symdef.algorithm = TPM2_ALG.LAST + 1 with self.assertRaises(ValueError) as e: crypto._symdef_to_crypt(symdef) self.assertEqual( str(e.exception), f"unsupported symmetric algorithm {TPM2_ALG.LAST + 1}" ) def test_ssh_key_ecc(self): eccpub = TPM2B_PUBLIC.from_pem(ssh_ecc_public) self.assertEqual(eccpub.publicArea.type, TPM2_ALG.ECC) self.assertEqual( eccpub.publicArea.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256 ) eccsens = TPM2B_SENSITIVE.from_pem(ssh_ecc_private) self.assertEqual(eccsens.sensitiveArea.sensitiveType, TPM2_ALG.ECC) def test_topem_encodings(self): pub = TPM2B_PUBLIC.from_pem(ecc_public_key) pem = pub.to_pem() self.assertTrue(pem.startswith(b"-----BEGIN PUBLIC KEY-----")) der = pub.to_der() self.assertTrue(der.startswith(b"0Y0\x13\x06\x07")) ssh = pub.to_ssh() self.assertTrue(ssh.startswith(b"ecdsa-sha2-nistp256")) with self.assertRaises(ValueError) as e: crypto._public_to_pem(pub.publicArea, encoding="madeup") self.assertEqual(str(e.exception), "unsupported encoding: madeup") def test_rsa_exponent(self): pub = TPMT_PUBLIC.from_pem(rsa_three_exponent) self.assertEqual(pub.parameters.rsaDetail.exponent, 3) key = crypto.public_to_key(pub) nums = key.public_numbers() self.assertEqual(nums.e, 3) def test_ecc_bad_curves(self): if not self._has_sect163r2: self.skipTest("cryptography doesn't support sect163r2") with self.assertRaises(ValueError) as e: TPMT_PUBLIC.from_pem(ecc_bad_curve) self.assertEqual(str(e.exception), "unsupported curve: sect163r2") pub = TPMT_PUBLIC.from_pem(ecc_public_key) pub.parameters.eccDetail.curveID = TPM2_ECC.NONE with self.assertRaises(ValueError) as e: pub.to_pem() self.assertEqual(str(e.exception), f"unsupported curve: {TPM2_ECC.NONE}") def test_unsupported_key(self): sl = dsa_private_key.strip().splitlines() b64 = b"".join(sl[1:-1]) der = b64decode(b64) with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.from_pem(der) self.assertEqual(str(e.exception), "unsupported key type: DSAPrivateKey") with self.assertRaises(ValueError) as e: TPMT_PUBLIC.from_pem(dsa_public_key) self.assertEqual(str(e.exception), "unsupported key type: DSAPublicKey") def test_from_pem_with_symmetric(self): sym = TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.AES) sym.keyBits.aes = 128 sym.mode.aes = TPM2_ALG.CFB pub = TPMT_PUBLIC.from_pem(ecc_public_key, symmetric=sym) self.assertEqual(pub.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES) self.assertEqual(pub.parameters.asymDetail.symmetric.keyBits.aes, 128) self.assertEqual(pub.parameters.asymDetail.symmetric.mode.aes, TPM2_ALG.CFB) def test_from_pem_with_scheme(self): scheme = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.ECDSA) scheme.details.ecdsa.hashAlg = TPM2_ALG.SHA256 pub = TPMT_PUBLIC.from_pem(ecc_public_key, scheme=scheme) self.assertEqual(pub.parameters.asymDetail.scheme.scheme, TPM2_ALG.ECDSA) self.assertEqual( pub.parameters.asymDetail.scheme.details.ecdsa.hashAlg, TPM2_ALG.SHA256 ) def test_public_from_private(self): pub = TPMT_PUBLIC.from_pem(rsa_private_key) self.assertEqual(pub.type, TPM2_ALG.RSA) self.assertEqual(pub.parameters.rsaDetail.keyBits, 2048) self.assertEqual(pub.parameters.rsaDetail.exponent, 0) self.assertEqual(pub.unique.rsa, rsa_public_key_bytes) pub = TPMT_PUBLIC.from_pem(ecc_private_key) self.assertEqual(pub.type, TPM2_ALG.ECC) self.assertEqual(pub.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256) self.assertEqual(pub.unique.ecc.x, ecc_public_key_bytes[0:32]) self.assertEqual(pub.unique.ecc.y, ecc_public_key_bytes[32:64]) def test_public_from_private_der(self): sl = rsa_private_key.strip().splitlines() b64 = b"".join(sl[1:-1]) rsader = b64decode(b64) pub = TPMT_PUBLIC.from_pem(rsader) self.assertEqual(pub.type, TPM2_ALG.RSA) self.assertEqual(pub.parameters.rsaDetail.keyBits, 2048) self.assertEqual(pub.parameters.rsaDetail.exponent, 0) self.assertEqual(pub.unique.rsa, rsa_public_key_bytes) sl = ecc_private_key.strip().splitlines() b64 = b"".join(sl[1:-1]) eccder = b64decode(b64) pub = TPMT_PUBLIC.from_pem(eccder) self.assertEqual(pub.type, TPM2_ALG.ECC) self.assertEqual(pub.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256) self.assertEqual(pub.unique.ecc.x, ecc_public_key_bytes[0:32]) self.assertEqual(pub.unique.ecc.y, ecc_public_key_bytes[32:64]) def test_encrypted_key(self): pub = TPMT_PUBLIC.from_pem(ecc_encrypted_key, password=b"mysecret") self.assertEqual(pub.type, TPM2_ALG.ECC) priv = TPMT_SENSITIVE.from_pem(ecc_encrypted_key, password=b"mysecret") self.assertEqual(priv.sensitiveType, TPM2_ALG.ECC) with self.assertRaises(ValueError): TPMT_PUBLIC.from_pem(ecc_encrypted_key, password=b"passpass") def test_keyedhash_from_secret(self): secret = b"secret key" scheme = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.HMAC) scheme.details.hmac.hashAlg = TPM2_ALG.SHA256 (sens, pub) = TPM2B_SENSITIVE.keyedhash_from_secret(secret, scheme=scheme) self.assertEqual(pub.publicArea.type, TPM2_ALG.KEYEDHASH) self.assertEqual(pub.publicArea.nameAlg, TPM2_ALG.SHA256) self.assertEqual( pub.publicArea.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.HMAC ) self.assertEqual( pub.publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg, TPM2_ALG.SHA256, ) self.assertEqual(sens.sensitiveArea.sensitiveType, TPM2_ALG.KEYEDHASH) self.assertEqual(sens.sensitiveArea.sensitive.bits, secret) def test_keyedhash_from_secret_unseal(self): secret = b"sealed secret" seed = b"\xF1" * 32 (sens, pub) = TPM2B_SENSITIVE.keyedhash_from_secret( secret, objectAttributes=TPMA_OBJECT.USERWITHAUTH, seed=seed ) handle = self.ectx.load_external(pub, sens) sealdata = self.ectx.unseal(handle) self.assertEqual(sens.sensitiveArea.seedValue, seed) self.assertEqual(sealdata, secret) def test_keyedhash_from_secret_bad(self): secret = b"1234" with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.keyedhash_from_secret(secret, nameAlg=TPM2_ALG.NULL) self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.NULL}" ) with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.keyedhash_from_secret(secret, seed=b"bad seed") self.assertEqual(str(e.exception), "invalid seed size, expected 32 but got 8") def test_symcipher_from_secret(self): secret = b"\xF1" * 32 sens, pub = TPM2B_SENSITIVE.symcipher_from_secret(secret) self.assertEqual(sens.sensitiveArea.sensitiveType, TPM2_ALG.SYMCIPHER) self.assertEqual(sens.sensitiveArea.sensitive.bits, secret) self.assertEqual(pub.publicArea.type, TPM2_ALG.SYMCIPHER) self.assertEqual(pub.publicArea.parameters.symDetail.sym.keyBits.sym, 256) self.assertEqual( pub.publicArea.parameters.symDetail.sym.algorithm, TPM2_ALG.AES ) self.assertEqual(pub.publicArea.parameters.symDetail.sym.mode.sym, TPM2_ALG.CFB) self.ectx.load_external(pub, sens) def test_symcipher_from_secret_bad(self): with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.symcipher_from_secret(b"\xFF" * 17) self.assertEqual( str(e.exception), "invalid key size, expected 128, 192 or 256 bits, got 136" ) with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.symcipher_from_secret(b"\xFF" * 32, algorithm=TPM2_ALG.SM4) self.assertEqual(str(e.exception), "invalid key size, expected 128, got 256") with self.assertRaises(ValueError) as e: TPMT_SENSITIVE.symcipher_from_secret(b"\xFF" * 32, seed=b"1234") self.assertEqual(str(e.exception), "invalid seed size, expected 32 but got 4") def test_verify_signature_hmac(self): secret = b"secret key" scheme = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.HMAC) scheme.details.hmac.hashAlg = TPM2_ALG.SHA256 (sens, pub) = TPM2B_SENSITIVE.keyedhash_from_secret( secret, scheme=scheme, objectAttributes=(TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH), ) handle = self.ectx.load_external(pub, sens) msg = b"sign me please" h = sha256(msg) sigdig = h.digest() sig = self.ectx.sign( handle, sigdig, TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), ) crypto._verify_signature(sig, secret, msg) sig.verify_signature(secret, sigdig, prehashed=True) def test_verify_signature_ecc(self): template = TPM2B_PUBLIC.parse( "ecc:ecdsa_sha256", objectAttributes=( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) handle, public, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), template ) msg = b"sign me please" h = sha256(msg) sigdig = h.digest() sig = self.ectx.sign( handle, sigdig, TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), None, ) crypto._verify_signature(sig, public, msg) crypto._verify_signature(sig, public, sigdig, prehashed=True) def test_verify_signature_rsapss(self): template = TPM2B_PUBLIC.parse( "rsa2048:rsapss-sha384:null", objectAttributes=( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) handle, public, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), template ) msg = b"sign me please" h = sha384(msg) sigdig = h.digest() sig = self.ectx.sign( handle, sigdig, TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL), ) crypto._verify_signature(sig, public, msg) crypto._verify_signature(sig, public, sigdig, prehashed=True) def test_verify_singature_rsassa(self): template = TPM2B_PUBLIC.parse( "rsa2048:rsassa-sha256:null", objectAttributes=( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) handle, public, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), template ) msg = b"sign me please" h = sha256(msg) sigdig = h.digest() sig = self.ectx.sign( handle, sigdig, TPMT_SIG_SCHEME(scheme=TPM2_ALG.NULL), TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL), ) sig.verify_signature(public, msg) sig.verify_signature(public, sigdig, prehashed=True) def test_verify_signature_bad(self): badalg = TPMT_SIGNATURE(sigAlg=TPM2_ALG.NULL) with self.assertRaises(ValueError) as e: crypto._verify_signature(badalg, b"", b"") self.assertEqual( str(e.exception), f"unsupported signature algorithm: {TPM2_ALG.NULL}" ) hsig = TPMT_SIGNATURE(sigAlg=TPM2_ALG.HMAC) hsig.signature.any.hashAlg = TPM2_ALG.SHA256 with self.assertRaises(ValueError) as e: crypto._verify_signature(hsig, str("not bytes"), b"1234") self.assertEqual( str(e.exception), f"bad key type for {TPM2_ALG.HMAC}, expected bytes, got str", ) hsig.signature.hmac.hashAlg = TPM2_ALG.NULL with self.assertRaises(ValueError) as e: crypto._verify_signature(hsig, b"key", b"1234") self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.NULL}" ) badecc = TPMT_SIGNATURE(sigAlg=TPM2_ALG.ECDSA) badecc.signature.any.hashAlg = TPM2_ALG.SHA256 with self.assertRaises(ValueError) as e: crypto._verify_signature(badecc, str("bad"), b"1234") self.assertEqual( str(e.exception), f"bad key type for {TPM2_ALG.ECDSA}, expected ECC public key, got str", ) ecckey = TPM2B_PUBLIC.from_pem(ecc_public_key) badecc.signature.ecdsa.hash = TPM2_ALG.NULL with self.assertRaises(ValueError) as e: crypto._verify_signature(badecc, ecckey, b"1234") self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.NULL}" ) badrsa = TPMT_SIGNATURE(sigAlg=TPM2_ALG.RSAPSS) badrsa.signature.any.hashAlg = TPM2_ALG.SHA256 with self.assertRaises(ValueError) as e: crypto._verify_signature(badrsa, str("bad"), b"1234") self.assertEqual( str(e.exception), f"bad key type for {TPM2_ALG.RSAPSS}, expected RSA public key, got str", ) badrsa.signature.rsapss.hash = TPM2_ALG.NULL rsakey = TPM2B_PUBLIC.from_pem(rsa_public_key) with self.assertRaises(ValueError) as e: crypto._verify_signature(badrsa, rsakey, b"1234") self.assertEqual( str(e.exception), f"unsupported digest algorithm: {TPM2_ALG.NULL}" ) badrsa.signature.rsapss.hash = TPM2_ALG.SHA256 with self.assertRaises(crypto.InvalidSignature): crypto._verify_signature(badrsa, rsakey, b"1234") badrsa.sigAlg = TPM2_ALG.RSASSA with self.assertRaises(crypto.InvalidSignature): crypto._verify_signature(badrsa, rsakey, b"1234") if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_cryptography.py000066400000000000000000000476331506405471500214050ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 from .TSS2_BaseTest import TSS2_EsapiTest from tpm2_pytss.constants import TPMA_OBJECT, TPM2_ECC, TPM2_ALG from tpm2_pytss.types import TPM2B_PUBLIC from tpm2_pytss.cryptography import tpm_rsa_private_key, tpm_ecc_private_key from cryptography.hazmat.primitives.asymmetric.padding import OAEP, MGF1, PKCS1v15, PSS from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric.utils import Prehashed from cryptography import x509 import datetime import copy rsa_template = TPM2B_PUBLIC.parse( "rsa2048", objectAttributes=TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.USERWITHAUTH, ) ecc_template = TPM2B_PUBLIC.parse( "ecc256", objectAttributes=TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.USERWITHAUTH, ) class TestCryptography(TSS2_EsapiTest): def test_rsa_key(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) self.assertEqual(privkey.key_size, 2048) with self.assertRaises(NotImplementedError) as e: privkey.private_numbers() with self.assertRaises(NotImplementedError) as e: privkey.private_bytes(encoding=None, format=None, encryption_algorithm=None) def test_rsa_decrypt_oaep(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) pubkey = privkey.public_key() padding = privkey.get_decryption_padding() encrypted_data = pubkey.encrypt(b"falafel", padding) decrypted_data = privkey.decrypt(encrypted_data, padding) self.assertEqual(decrypted_data, b"falafel") def test_rsa_decrypt_pkcs1v15(self): rsaes = TPM2B_PUBLIC(rsa_template) rsaes.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSAES rsaes.publicArea.objectAttributes ^= TPMA_OBJECT.SIGN_ENCRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsaes ) privkey = tpm_rsa_private_key(self.ectx, handle) pubkey = privkey.public_key() padding = privkey.get_decryption_padding() encrypted_data = pubkey.encrypt(b"falafel", padding) decrypted_data = privkey.decrypt(encrypted_data, padding) self.assertEqual(decrypted_data, b"falafel") def test_rsa_key_bad_type(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) with self.assertRaises(ValueError) as e: tpm_rsa_private_key(self.ectx, handle) self.assertEqual(str(e.exception), "invalid key type, expected rsa, got ecc") def test_rsa_key_restricted(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public="rsa2048" ) with self.assertRaises(ValueError) as e: tpm_rsa_private_key(self.ectx, handle) self.assertEqual( str(e.exception), "TPM key does not allow generic signing and/or decryption (object attribute restricted is set)", ) def test_rsa_sign_pss(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) pubkey = privkey.public_key() padding = privkey.get_signature_padding() halg = privkey.get_digest_algorithm() sig = privkey.sign(b"falafel", padding, halg()) pubkey.verify(sig, b"falafel", padding, halg()) def test_rsa_sign_pkcs1v15(self): rsassa = TPM2B_PUBLIC(rsa_template) rsassa.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSASSA rsassa.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = ( TPM2_ALG.SHA384 ) rsassa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsassa ) privkey = tpm_rsa_private_key(self.ectx, handle) pubkey = privkey.public_key() padding = privkey.get_signature_padding() halg = privkey.get_digest_algorithm() sig = privkey.sign(b"falafel", padding, halg()) pubkey.verify(sig, b"falafel", padding, halg()) def test_rsa_no_decrypt(self): rsa_no_decrypt = TPM2B_PUBLIC(rsa_template) rsa_no_decrypt.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_no_decrypt ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = PKCS1v15() with self.assertRaises(ValueError) as e: privkey.decrypt(b"falafel", padding) self.assertEqual( str(e.exception), "TPM key does not allow decryption (object attribute decrypt is not set)", ) def test_rsa_no_sign(self): rsa_no_sign = TPM2B_PUBLIC(rsa_template) rsa_no_sign.publicArea.objectAttributes ^= TPMA_OBJECT.SIGN_ENCRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_no_sign ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = PKCS1v15() halg = privkey.get_digest_algorithm() with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", padding, halg()) self.assertEqual( str(e.exception), "TPM key does not allow signing (object attribute sign_encrypt is not set)", ) def test_rsa_prehashed(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = PKCS1v15() halg = privkey.get_digest_algorithm() with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", padding, Prehashed(halg())) self.assertEqual(str(e.exception), "Prehashed data is not supported") def test_rsa_unsupported_sig_scheme(self): rsaes = TPM2B_PUBLIC(rsa_template) rsaes.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSAES rsaes.publicArea.objectAttributes ^= TPMA_OBJECT.SIGN_ENCRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsaes ) privkey = tpm_rsa_private_key(self.ectx, handle) with self.assertRaises(ValueError) as e: privkey.get_signature_padding() self.assertEqual(str(e.exception), "unsupported signature scheme rsaes") def test_rsa_unsupported_decrypt_scheme(self): rsassa = TPM2B_PUBLIC(rsa_template) rsassa.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSASSA rsassa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsassa ) privkey = tpm_rsa_private_key(self.ectx, handle) with self.assertRaises(ValueError) as e: privkey.get_decryption_padding() self.assertEqual(str(e.exception), "unsupported decryption scheme rsassa") def test_ecc_key(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) self.assertEqual(privkey.key_size, 256) self.assertIsInstance(privkey.curve, ec.SECP256R1) with self.assertRaises(NotImplementedError) as e: privkey.private_numbers() with self.assertRaises(NotImplementedError) as e: privkey.private_bytes(encoding=None, format=None, encryption_algorithm=None) def test_ecc_key_bad_type(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) with self.assertRaises(ValueError) as e: tpm_ecc_private_key(self.ectx, handle) self.assertEqual(str(e.exception), "invalid key type, expected ecc, got rsa") def test_ecc_key_restricted(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public="ecc256" ) with self.assertRaises(ValueError) as e: tpm_ecc_private_key(self.ectx, handle) self.assertEqual( str(e.exception), "TPM key does not allow generic signing and/or decryption (object attribute restricted is set)", ) def test_ecc_exchange(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) peer_key = ec.generate_private_key(privkey.curve) peer_public_key = peer_key.public_key() tpm_shared_key = privkey.exchange(ec.ECDH(), peer_public_key) pyca_shared_key = peer_key.exchange(ec.ECDH(), privkey.public_key()) self.assertEqual(tpm_shared_key, pyca_shared_key) def test_ecc_sign(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) pubkey = privkey.public_key() sigalg = privkey.get_signature_algorithm() sig = privkey.sign(b"falafel", sigalg) pubkey.verify(sig, b"falafel", sigalg) def test_ecc_sign_with_scheme(self): ecc_ecdsa = TPM2B_PUBLIC(ecc_template) ecc_ecdsa.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA ecc_ecdsa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_ecdsa ) privkey = tpm_ecc_private_key(self.ectx, handle) pubkey = privkey.public_key() sigalg = privkey.get_signature_algorithm() sig = privkey.sign(b"falafel", sigalg) pubkey.verify(sig, b"falafel", sigalg) def test_ecc_no_decrypt(self): ecc_no_decrypt = TPM2B_PUBLIC(ecc_template) ecc_no_decrypt.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_no_decrypt ) privkey = tpm_ecc_private_key(self.ectx, handle) peer_key = ec.generate_private_key(privkey.curve) peer_public_key = peer_key.public_key() with self.assertRaises(ValueError) as e: privkey.exchange(ec.ECDH(), peer_public_key) self.assertEqual( str(e.exception), "TPM key does not allow ECDH key exchange (object attribute decrypt is not set)", ) def test_ecc_different_curves(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) peer_key = ec.generate_private_key(ec.SECP384R1()) peer_public_key = peer_key.public_key() with self.assertRaises(ValueError) as e: privkey.exchange(ec.ECDH(), peer_public_key) self.assertEqual( str(e.exception), "curve mismatch for peer key, got secp384r1, expected secp256r1", ) def test_ecc_no_sign(self): ecc_no_sign = TPM2B_PUBLIC(ecc_template) ecc_no_sign.publicArea.objectAttributes ^= TPMA_OBJECT.SIGN_ENCRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_no_sign ) privkey = tpm_ecc_private_key(self.ectx, handle) halg = privkey.get_digest_algorithm() sigalg = ec.ECDSA(halg()) with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", sigalg) self.assertEqual( str(e.exception), "TPM key does not allow signing (object attribute sign_encrypt is not set)", ) def test_ecc_prehashed(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) halg = privkey.get_digest_algorithm() sigalg = ec.ECDSA(Prehashed(halg())) with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", sigalg) self.assertEqual(str(e.exception), "Prehashed data is not supported") def test_ecc_unsupported_curve(self): ecc_brainpool = TPM2B_PUBLIC(ecc_template) ecc_brainpool.publicArea.parameters.eccDetail.curveID = TPM2_ECC.BN_P256 handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_brainpool ) with self.assertRaises(ValueError) as e: tpm_ecc_private_key(self.ectx, handle) self.assertEqual(str(e.exception), "unsupported curve bn_p256") def test_ecc_unsupported_scheme(self): ecc_ecdaa = TPM2B_PUBLIC(ecc_template) ecc_ecdaa.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDAA ecc_ecdaa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_ecdaa ) privkey = tpm_ecc_private_key(self.ectx, handle) with self.assertRaises(ValueError) as e: privkey.get_signature_algorithm() self.assertEqual(str(e.exception), "unsupported signature scheme ecdaa") def test_scheme_mismatch(self): rsassa = TPM2B_PUBLIC(rsa_template) rsassa.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSASSA rsassa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsassa ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = PSS( mgf=MGF1(algorithm=hashes.SHA256()), salt_length=PSS.DIGEST_LENGTH ) with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", padding, hashes.SHA256()) self.assertEqual( str(e.exception), "invalid scheme, scheme has rsapss but key requires rsassa", ) def test_scheme_digest_mismatch(self): rsassa = TPM2B_PUBLIC(rsa_template) rsassa.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.RSASSA rsassa.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = ( TPM2_ALG.SHA1 ) rsassa.publicArea.objectAttributes ^= TPMA_OBJECT.DECRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsassa ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = PKCS1v15() with self.assertRaises(ValueError) as e: privkey.sign(b"falafel", padding, hashes.SHA256()) self.assertEqual( str(e.exception), "digest algorithm mismatch, scheme has sha256 but key requires sha", ) def test_scheme_digest_mismatch_oaep(self): rsa_oaep = TPM2B_PUBLIC(rsa_template) rsa_oaep.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG.OAEP rsa_oaep.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = ( TPM2_ALG.SHA256 ) rsa_oaep.publicArea.objectAttributes ^= TPMA_OBJECT.SIGN_ENCRYPT handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_oaep ) privkey = tpm_rsa_private_key(self.ectx, handle) padding = OAEP( mgf=MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA384(), label=b"" ) with self.assertRaises(ValueError) as e: privkey.decrypt(b"falafel", padding) self.assertEqual( str(e.exception), "digest algorithm mismatch, scheme has sha384 but key requires sha256", ) def test_cert_builder_rsa(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) pubkey = privkey.public_key() builder = x509.CertificateBuilder() builder = builder.subject_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) builder = builder.issuer_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) builder = builder.serial_number(x509.random_serial_number()) one_day = datetime.timedelta(1, 0, 0) builder = builder.not_valid_before(datetime.datetime.today() - one_day) builder = builder.not_valid_after(datetime.datetime.today() + one_day) builder = builder.public_key(pubkey) halg = privkey.get_digest_algorithm() cert = builder.sign(privkey, algorithm=halg()) cert.verify_directly_issued_by(cert) def test_csr_builder_rsa(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) builder = x509.CertificateSigningRequestBuilder() builder = builder.subject_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) halg = privkey.get_digest_algorithm() csr = builder.sign(privkey, algorithm=halg()) self.assertEqual(csr.is_signature_valid, True) def test_cert_builder_ecc(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) pubkey = privkey.public_key() builder = x509.CertificateBuilder() builder = builder.subject_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) builder = builder.issuer_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) builder = builder.serial_number(x509.random_serial_number()) one_day = datetime.timedelta(1, 0, 0) builder = builder.not_valid_before(datetime.datetime.today() - one_day) builder = builder.not_valid_after(datetime.datetime.today() + one_day) builder = builder.public_key(pubkey) halg = privkey.get_digest_algorithm() cert = builder.sign(privkey, algorithm=halg()) cert.verify_directly_issued_by(cert) def test_csr_builder_ecc(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) builder = x509.CertificateSigningRequestBuilder() builder = builder.subject_name( x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "falafel")]) ) halg = privkey.get_digest_algorithm() csr = builder.sign(privkey, algorithm=halg()) self.assertEqual(csr.is_signature_valid, True) def test_rsa_copy(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=rsa_template ) privkey = tpm_rsa_private_key(self.ectx, handle) privkey_copy = copy.copy(privkey) self.assertEqual(privkey.key_size, privkey_copy.key_size) def test_ecc_copy(self): handle, _, _, _, _ = self.ectx.create_primary( in_sensitive=None, in_public=ecc_template ) privkey = tpm_ecc_private_key(self.ectx, handle) privkey_copy = copy.copy(privkey) self.assertEqual(type(privkey.curve), type(privkey_copy.curve)) tpm2-pytss-3.0.0-rc0/test/test_encoding.py000066400000000000000000000612741506405471500204350ustar00rootroot00000000000000#!/usr/bin/python3 -u """ SPDX-License-Identifier: BSD-2 """ import unittest from tpm2_pytss import * from tpm2_pytss.encoding import ( base_encdec, json_encdec, ) class SerializationTest(unittest.TestCase): def test_base_simple_tpm2b(self): enc = base_encdec() dig = TPM2B_DIGEST(b"falafel") ev = enc.encode(dig) self.assertEqual(ev, "66616c6166656c") def test_base_friendly_int(self): enc = base_encdec() ev = enc.encode(TPM2_ALG.SHA256) self.assertEqual(ev, 0x0B) def test_base_friendly_intlist(self): enc = base_encdec() ev = enc.encode(TPMA_OBJECT(TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM)) self.assertEqual(ev, 0x10002) def test_base_int(self): enc = base_encdec() ev = enc.encode(1337) self.assertEqual(ev, 1337) def test_base_complex_tpm2b(self): enc = base_encdec() p = TPM2B_ECC_POINT(TPMS_ECC_POINT(x=b"\x01", y="\x02")) ev = enc.encode(p) self.assertEqual(ev, {"x": "01", "y": "02"}) def test_base_tpml(self): enc = base_encdec() al = TPML_ALG((TPM2_ALG.SHA256, TPM2_ALG.SHA384, TPM2_ALG.SHA512)) ev = enc.encode(al) self.assertEqual(ev, [TPM2_ALG.SHA256, TPM2_ALG.SHA384, TPM2_ALG.SHA512]) def test_base_TPMS_CAPABILITY_DATA(self): enc = base_encdec() algs = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.ALGS) algs.data.algorithms = TPML_ALG_PROPERTY( (TPMS_ALG_PROPERTY(alg=TPM2_ALG.SHA256, algProperties=TPMA_ALGORITHM.HASH),) ) ev = enc.encode(algs) self.assertEqual( ev, {"capability": 0, "data": [{"alg": 11, "algProperties": 4}]} ) handles = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.HANDLES) handles.data.handles = TPML_HANDLE((1,)) ev = enc.encode(handles) self.assertEqual(ev, {"capability": 1, "data": [1]}) commands = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.COMMANDS) cmd = TPM2_CC.NV_Write & TPMA_CC.NV & (2 << TPMA_CC.CHANDLES_SHIFT) commands.data.command = TPML_CCA((cmd,)) ev = enc.encode(commands) self.assertEqual(ev, {"capability": 2, "data": [cmd]}) ppcommands = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.PP_COMMANDS) ppcommands.data.ppCommands = TPML_CC((3,)) ev = enc.encode(ppcommands) self.assertEqual(ev, {"capability": 3, "data": [3]}) auditcommands = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.AUDIT_COMMANDS) auditcommands.data.auditCommands = TPML_CC((4,)) ev = enc.encode(auditcommands) self.assertEqual(ev, {"capability": 4, "data": [4]}) pcrs = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.PCRS) pcrsel = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA256, sizeofSelect=3, pcrSelect=b"\x81\x00\x00" ) pcrs.data.assignedPCR = TPML_PCR_SELECTION((pcrsel,)) ev = enc.encode(pcrs) self.assertEqual( ev, {"capability": 5, "data": [{"hash": 0x0B, "pcrSelect": [0, 7]}]} ) tpm = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.TPM_PROPERTIES) prop = TPMS_TAGGED_PROPERTY(property=TPM2_PT_NV.BUFFER_MAX, value=0x300) tpm.data.tpmProperties = TPML_TAGGED_TPM_PROPERTY((prop,)) ev = enc.encode(tpm) self.assertEqual( ev, {"capability": 6, "data": [{"property": 300, "value": 0x300}]} ) pcrs = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.PCR_PROPERTIES) pprop = TPMS_TAGGED_PCR_SELECT( tag=TPM2_PT_PCR.DRTM_RESET, sizeofSelect=3, pcrSelect=b"\xFF\x00\x00" ) pcrs.data.pcrProperties = TPML_TAGGED_PCR_PROPERTY((pprop,)) ev = enc.encode(pcrs) self.assertEqual( ev, { "capability": 7, "data": [{"tag": 0x12, "pcrSelect": [0, 1, 2, 3, 4, 5, 6, 7]}], }, ) curves = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.ECC_CURVES) curves.data.eccCurves = TPML_ECC_CURVE((TPM2_ECC.SM2_P256,)) ev = enc.encode(curves) self.assertEqual(ev, {"capability": 8, "data": [0x20]}) def test_base_TPMS_ATTEST(self): enc = base_encdec() certify = TPMS_ATTEST(type=TPM2_ST.ATTEST_CERTIFY) certify.attested.certify = TPMS_CERTIFY_INFO( name=b"\x01", qualifiedName=b"\x02" ) ev = enc.encode(certify) self.assertEqual(ev["type"], 0x8017) self.assertEqual(ev["attested"], {"name": "01", "qualifiedName": "02"}) creation = TPMS_ATTEST(type=TPM2_ST.ATTEST_CREATION) creation.attested.creation = TPMS_CREATION_INFO( objectName=b"\x01", creationHash=b"\x02" ) ev = enc.encode(creation) self.assertEqual(ev["type"], 0x801A) self.assertEqual(ev["attested"], {"objectName": "01", "creationHash": "02"}) quote = TPMS_ATTEST(type=TPM2_ST.ATTEST_QUOTE) sel = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA256, sizeofSelect=3, pcrSelect=b"\x00\x81\x00" ) quote.attested.quote = TPMS_QUOTE_INFO( pcrSelect=TPML_PCR_SELECTION((sel,)), pcrDigest=b"\x01" * 32 ) ev = enc.encode(quote) self.assertEqual(ev["type"], 0x8018) self.assertEqual( ev["attested"], { "pcrSelect": [{"hash": TPM2_ALG.SHA256, "pcrSelect": [8, 15]}], "pcrDigest": "01" * 32, }, ) command = TPMS_ATTEST(type=TPM2_ST.ATTEST_COMMAND_AUDIT) command.attested.commandAudit = TPMS_COMMAND_AUDIT_INFO( auditCounter=1337, digestAlg=TPM2_ALG.SHA256, auditDigest=b"\x01", commandDigest=b"\x02", ) ev = enc.encode(command) self.assertEqual(ev["type"], TPM2_ST.ATTEST_COMMAND_AUDIT) self.assertEqual( ev["attested"], { "auditCounter": 1337, "digestAlg": TPM2_ALG.SHA256, "auditDigest": "01", "commandDigest": "02", }, ) session = TPMS_ATTEST(type=TPM2_ST.ATTEST_SESSION_AUDIT) session.attested.sessionAudit = TPMS_SESSION_AUDIT_INFO( exclusiveSession=True, sessionDigest=b"\x01" ) ev = enc.encode(session) self.assertEqual(ev["type"], TPM2_ST.ATTEST_SESSION_AUDIT) self.assertEqual(ev["attested"], {"exclusiveSession": 1, "sessionDigest": "01"}) time = TPMS_ATTEST(type=TPM2_ST.ATTEST_TIME) time.attested.time = TPMS_TIME_ATTEST_INFO( time=TPMS_TIME_INFO( time=1234, clockInfo=TPMS_CLOCK_INFO( clock=1024, resetCount=2, restartCount=3, safe=False ), ), firmwareVersion=1337, ) ev = enc.encode(time) self.assertEqual(ev["type"], TPM2_ST.ATTEST_TIME) self.assertEqual( ev["attested"], { "firmwareVersion": 1337, "time": { "time": 1234, "clockInfo": { "clock": 1024, "resetCount": 2, "restartCount": 3, "safe": 0, }, }, }, ) nv = TPMS_ATTEST(type=TPM2_ST.ATTEST_NV) nv.attested.nv = TPMS_NV_CERTIFY_INFO( indexName=b"\x01", offset=2, nvContents=b"\x03" ) ev = enc.encode(nv) self.assertEqual(ev["type"], TPM2_ST.ATTEST_NV) self.assertEqual( ev["attested"], {"indexName": "01", "offset": 2, "nvContents": "03"} ) def test_base_TPMT_SYM_DEF(self): enc = base_encdec() sym = TPMT_SYM_DEF(algorithm=TPM2_ALG.AES) sym.keyBits.aes = 128 sym.mode.aes = TPM2_ALG.CFB ev = enc.encode(sym) self.assertEqual( ev, {"algorithm": TPM2_ALG.AES, "keyBits": 128, "mode": TPM2_ALG.CFB} ) xor = TPMT_SYM_DEF(algorithm=TPM2_ALG.XOR) xor.keyBits.exclusiveOr = TPM2_ALG.SHA1 ev = enc.encode(xor) self.assertEqual(ev, {"algorithm": TPM2_ALG.XOR, "keyBits": TPM2_ALG.SHA1}) def test_base_TPMT_KEYEDHASH_SCHEME(self): enc = base_encdec() hmac = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.HMAC) hmac.details.hmac.hashAlg = TPM2_ALG.SHA256 ev = enc.encode(hmac) self.assertEqual( ev, {"scheme": TPM2_ALG.HMAC, "details": {"hashAlg": TPM2_ALG.SHA256}} ) xor = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.XOR) xor.details.exclusiveOr = TPMS_SCHEME_XOR( hashAlg=TPM2_ALG.SHA256, kdf=TPM2_ALG.KDF2 ) ev = enc.encode(xor) self.assertEqual( ev, { "scheme": TPM2_ALG.XOR, "details": {"hashAlg": TPM2_ALG.SHA256, "kdf": TPM2_ALG.KDF2}, }, ) def test_base_TPMT_SIG_SCHEME(self): enc = base_encdec() ecdaa = TPMT_SIG_SCHEME(scheme=TPM2_ALG.ECDAA) ecdaa.details.ecdaa = TPMS_SCHEME_ECDAA(hashAlg=TPM2_ALG.SHA256, count=2) ev = enc.encode(ecdaa) self.assertEqual( ev, { "scheme": TPM2_ALG.ECDAA, "details": {"hashAlg": TPM2_ALG.SHA256, "count": 2}, }, ) sig = TPMT_SIG_SCHEME(scheme=TPM2_ALG.ECDSA) sig.details.any.hashAlg = TPM2_ALG.SHA256 ev = enc.encode(sig) self.assertEqual( ev, {"scheme": TPM2_ALG.ECDSA, "details": {"hashAlg": TPM2_ALG.SHA256}} ) def test_base_TPMT_KDF_SCHEME(self): enc = base_encdec() kdf = TPMT_KDF_SCHEME(scheme=TPM2_ALG.KDF2) kdf.details.mgf1.hashAlg = TPM2_ALG.SHA256 ev = enc.encode(kdf) self.assertEqual( ev, {"scheme": TPM2_ALG.KDF2, "details": {"hashAlg": TPM2_ALG.SHA256}} ) def test_base_TPMT_ASYM_SCHEME(self): enc = base_encdec() ecdaa = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.ECDAA) ecdaa.details.ecdaa = TPMS_SCHEME_ECDAA(hashAlg=TPM2_ALG.SHA256, count=2) ev = enc.encode(ecdaa) self.assertEqual( ev, { "scheme": TPM2_ALG.ECDAA, "details": {"count": 2, "hashAlg": TPM2_ALG.SHA256}, }, ) rsaes = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.RSAES) ev = enc.encode(rsaes) self.assertEqual(ev, {"scheme": TPM2_ALG.RSAES}) scheme = TPMT_ASYM_SCHEME(scheme=TPM2_ALG.RSASSA) scheme.details.rsassa.hashAlg = TPM2_ALG.SHA256 ev = enc.encode(scheme) self.assertEqual( ev, {"scheme": TPM2_ALG.RSASSA, "details": {"hashAlg": TPM2_ALG.SHA256}} ) def test_base_TPMT_SINGATURE(self): enc = base_encdec() rsa = TPMT_SIGNATURE(sigAlg=TPM2_ALG.RSASSA) rsa.signature.rsassa = TPMS_SIGNATURE_RSA(hash=TPM2_ALG.SHA256, sig=b"\x01") ev = enc.encode(rsa) self.assertEqual( ev, { "sigAlg": TPM2_ALG.RSASSA, "signature": {"hash": TPM2_ALG.SHA256, "sig": "01"}, }, ) ecc = TPMT_SIGNATURE(sigAlg=TPM2_ALG.ECDSA) ecc.signature.ecdsa = TPMS_SIGNATURE_ECC( hash=TPM2_ALG.SHA256, signatureR=b"\x02", signatureS=b"\x03" ) ev = enc.encode(ecc) self.assertEqual( ev, { "sigAlg": TPM2_ALG.ECDSA, "signature": { "hash": TPM2_ALG.SHA256, "signatureR": "02", "signatureS": "03", }, }, ) hmac = TPMT_SIGNATURE(sigAlg=TPM2_ALG.HMAC) hmac.signature.hmac.hashAlg = TPM2_ALG.SHA256 hmac.signature.hmac.digest.sha256 = b"\x01" * 32 ev = enc.encode(hmac) self.assertEqual( ev, { "sigAlg": TPM2_ALG.HMAC, "signature": {"hashAlg": TPM2_ALG.SHA256, "digest": "01" * 32}, }, ) def test_base_TPMT_PUBLIC_PARMS(self): enc = base_encdec() keyedhash = TPMT_PUBLIC_PARMS(type=TPM2_ALG.KEYEDHASH) keyedhash.parameters.keyedHashDetail.scheme = TPMT_KEYEDHASH_SCHEME( scheme=TPM2_ALG.HMAC ) keyedhash.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = ( TPM2_ALG.SHA256 ) ev = enc.encode(keyedhash) self.assertEqual(ev["type"], TPM2_ALG.KEYEDHASH) self.assertEqual( ev["parameters"], { "scheme": { "details": {"hashAlg": TPM2_ALG.SHA256}, "scheme": TPM2_ALG.HMAC, }, }, ) sym = TPMT_PUBLIC_PARMS(type=TPM2_ALG.SYMCIPHER) sym.parameters.symDetail.sym = TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.AES) sym.parameters.symDetail.sym.keyBits.aes = 128 sym.parameters.symDetail.sym.mode.aes = TPM2_ALG.CFB ev = enc.encode(sym) self.assertEqual(ev["type"], TPM2_ALG.SYMCIPHER) self.assertEqual( ev["parameters"], {"sym": {"algorithm": TPM2_ALG.AES, "keyBits": 128, "mode": TPM2_ALG.CFB}}, ) rsa = TPMT_PUBLIC_PARMS(type=TPM2_ALG.RSA) parms = TPMS_RSA_PARMS(keyBits=2048) parms.symmetric.algorithm = TPM2_ALG.NULL parms.scheme.scheme = TPM2_ALG.NULL rsa.parameters.rsaDetail = parms ev = enc.encode(rsa) self.assertEqual(ev["type"], TPM2_ALG.RSA) self.assertEqual( ev["parameters"], { "exponent": 0, "keyBits": 2048, "scheme": {"scheme": TPM2_ALG.NULL}, "symmetric": {"algorithm": TPM2_ALG.NULL}, }, ) ecc = TPMT_PUBLIC_PARMS(type=TPM2_ALG.ECC) parms = TPMS_ECC_PARMS(curveID=TPM2_ALG.SM2) parms.symmetric.algorithm = TPM2_ALG.NULL parms.scheme.scheme = TPM2_ALG.NULL parms.kdf.scheme = TPM2_ALG.NULL ecc.parameters.eccDetail = parms ev = enc.encode(ecc) self.assertEqual(ev["type"], TPM2_ALG.ECC) self.assertEqual( ev["parameters"], { "curveID": TPM2_ALG.SM2, "kdf": {"scheme": TPM2_ALG.NULL}, "scheme": {"scheme": TPM2_ALG.NULL}, "symmetric": {"algorithm": TPM2_ALG.NULL}, }, ) def test_base_TPMT_PUBLIC(self): enc = base_encdec() keyedhash = TPMT_PUBLIC(type=TPM2_ALG.KEYEDHASH) keyedhash.unique.keyedHash = b"\x22" * 32 keyedhash.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.NULL ev = enc.encode(keyedhash) self.assertEqual(ev["type"], TPM2_ALG.KEYEDHASH) self.assertEqual(ev["unique"], "22" * 32) rsa = TPMT_PUBLIC(type=TPM2_ALG.RSA) rsa.unique.rsa = b"\x33" * 32 ev = enc.encode(rsa) self.assertEqual(ev["type"], TPM2_ALG.RSA) self.assertEqual(ev["unique"], "33" * 32) ecc = TPMT_PUBLIC(type=TPM2_ALG.ECC) ecc.unique.ecc.x = b"\x04" ecc.unique.ecc.y = b"\x05" ev = enc.encode(ecc) self.assertEqual(ev["type"], TPM2_ALG.ECC) self.assertEqual(ev["unique"], {"x": "04", "y": "05"}) def test_base_TPMT_SENSITIVE(self): enc = base_encdec() rsa = TPMT_SENSITIVE(sensitiveType=TPM2_ALG.RSA) rsa.sensitive.rsa = b"\x11" * 32 ev = enc.encode(rsa) self.assertEqual(ev["sensitiveType"], TPM2_ALG.RSA) self.assertEqual(ev["sensitive"], "11" * 32) def test_base_bad(self): enc = base_encdec() with self.assertRaises(TypeError) as e: enc.encode(TPMU_KDF_SCHEME()) self.assertEqual(str(e.exception), "tried to encode union TPMU_KDF_SCHEME") with self.assertRaises(ValueError) as e: null = TPMT_PUBLIC(type=TPM2_ALG.NULL) enc.encode(null) self.assertEqual( str(e.exception), "unable to find union selector for field parameters in TPMT_PUBLIC", ) with self.assertRaises(TypeError) as e: enc.encode(list()) self.assertEqual(str(e.exception), "unable to encode value of type list") def test_base_decode_friendly_intlist(self): dec = base_encdec() attrs = int(TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.DECRYPT) dv = dec.decode(TPMA_OBJECT(), attrs) self.assertEqual(dv, TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.DECRYPT) self.assertIsInstance(dv, TPMA_OBJECT) def test_base_decode_friendly_int(self): dec = base_encdec() alg = int(TPM2_ALG.SHA256) dv = dec.decode(TPM2_ALG(), alg) self.assertEqual(dv, TPM2_ALG.SHA256) self.assertIsInstance(dv, TPM2_ALG) def test_base_decode_int(self): dec = base_encdec() i = 1234 dv = dec.decode(int(), i) self.assertEqual(dv, 1234) self.assertIsInstance(dv, int) def test_base_decode_simple_tpm2b(self): dec = base_encdec() hstr = "01020304" dv = dec.decode(TPM2B_DIGEST(), hstr) self.assertEqual(dv.buffer, b"\x01\x02\x03\x04") self.assertEqual(dv.size, 4) self.assertIsInstance(dv, TPM2B_DIGEST) def test_base_decode_complex_tpm2b(self): dec = base_encdec() points = {"x": "01", "y": "02"} dv = dec.decode(TPM2B_ECC_POINT(), points) self.assertEqual(dv.point.x, b"\x01") self.assertEqual(dv.point.y, b"\x02") self.assertIsInstance(dv, TPM2B_ECC_POINT) def test_base_decode_tpml(self): dec = base_encdec() cmds = (int(TPM2_CC.Create), int(TPM2_CC.CreatePrimary)) dv = dec.decode(TPML_CC(), cmds) self.assertEqual(len(dv), 2) self.assertIsInstance(dv, TPML_CC) self.assertEqual(dv[0], TPM2_CC.Create) self.assertEqual(dv[1], TPM2_CC.CreatePrimary) self.assertIsInstance(dv[0], TPM2_CC) self.assertIsInstance(dv[1], TPM2_CC) def test_base_decode_struct(self): dec = base_encdec() templ = {"type": TPM2_ALG.RSA, "parameters": {"exponent": 1234, "keyBits": 1}} dv = dec.decode(TPMT_PUBLIC_PARMS(), templ) self.assertIsInstance(dv, TPMT_PUBLIC_PARMS) self.assertEqual(dv.type, TPM2_ALG.RSA) self.assertEqual(dv.parameters.rsaDetail.exponent, 1234) self.assertEqual(dv.parameters.rsaDetail.keyBits, 1) def test_base_decode_pcrselect(self): dec = base_encdec() sel = {"pcrSelect": [8, 15]} dv = dec.decode(TPMS_PCR_SELECT(), sel) self.assertEqual(dv.sizeofSelect, 2) self.assertEqual(bytes(dv.pcrSelect), b"\x00\x81\x00\x00") def test_base_decode_strict(self): points = {"x": "01", "y": "02", "z": "03"} decoder = base_encdec(strict=True) with self.assertRaises(ValueError) as e: decoder.decode(TPMS_ECC_POINT(), points) self.assertEqual(str(e.exception), "unknown field(s) z in source") def test_base_decode_case_insensitive(self): points = {"X": "01", "Y": "02"} dec = base_encdec(case_insensitive=True) dv = dec.decode(TPMS_ECC_POINT(), points) self.assertEqual(dv.x, b"\x01") self.assertEqual(dv.y, b"\x02") def test_base_decode_bad(self): dec = base_encdec() with self.assertRaises(TypeError) as e: dec.decode(TPMU_KDF_SCHEME(), {}) self.assertEqual(str(e.exception), "tried to decode union TPMU_KDF_SCHEME") with self.assertRaises(TypeError) as e: dec.decode("", {}) self.assertEqual(str(e.exception), "unable to decode value of type str") def test_base_bad_selector(self): enc = base_encdec() cap = TPMS_CAPABILITY_DATA(capability=TPM2_CAP.VENDOR_PROPERTY + 1) with self.assertRaises(ValueError) as e: enc.encode(cap) self.assertEqual( str(e.exception), "unable to find union selector for field data in TPMS_CAPABILITY_DATA", ) att = TPMS_ATTEST(type=TPM2_ST.FU_MANIFEST + 1) with self.assertRaises(ValueError) as e: enc.encode(att) self.assertEqual( str(e.exception), "unable to find union selector for field attested in TPMS_ATTEST", ) keyed = TPMT_KEYEDHASH_SCHEME(scheme=TPM2_ALG.LAST + 1) with self.assertRaises(ValueError) as e: enc.encode(keyed) self.assertEqual( str(e.exception), "unable to find union selector for field details in TPMT_KEYEDHASH_SCHEME", ) sig = TPMT_SIGNATURE(sigAlg=TPM2_ALG.LAST + 1) with self.assertRaises(ValueError) as e: enc.encode(sig) self.assertEqual( str(e.exception), "unable to find union selector for field signature in TPMT_SIGNATURE", ) dec = base_encdec() with self.assertRaises(ValueError) as e: dec._get_by_selector(TPMT_PUBLIC(), "badfield") self.assertEqual( str(e.exception), "unable to find union selector for field badfield in TPMT_PUBLIC", ) with self.assertRaises(ValueError) as e: dec._get_by_selector(TPMT_PUBLIC(type=TPM2_ALG.NULL), "unique") self.assertEqual( str(e.exception), "unable to find union selector for field unique in TPMT_PUBLIC", ) def test_json_enc_int(self): enc = json_encdec() ev = enc.encode(1234) self.assertEqual(ev, 1234) ev = enc.encode(0x100000002) self.assertEqual(ev, [1, 2]) def test_json_enc_friendly_int(self): enc = json_encdec() ev = enc.encode(TPM2_RH.OWNER) self.assertEqual(ev, "owner") ev = enc.encode(TPM2_ALG.LAST + 1) self.assertIsInstance(ev, int) self.assertEqual(ev, int(TPM2_ALG.LAST + 1)) ev = enc.encode(TPM2_GENERATED.VALUE) self.assertEqual(ev, "value") def test_json_enc_friendly_intlist(self): enc = json_encdec() ev = enc.encode(TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.RESTRICTED) self.assertEqual(ev, {"userwithauth": 1, "restricted": 1}) ev = enc.encode(TPMA_NV.AUTHREAD | TPM2_NT.COUNTER << TPMA_NV.TPM2_NT_SHIFT) self.assertEqual(ev, {"authread": 1, "nt": "counter"}) ev = enc.encode(TPMA_CC.NV | 5 << TPMA_CC.CHANDLES_SHIFT | 1234) self.assertEqual(ev, {"nv": 1, "chandles": 5, "commandindex": 1234}) ev = enc.encode( TPMA_LOCALITY.ZERO | TPMA_LOCALITY(5 << TPMA_LOCALITY.EXTENDED_SHIFT) ) self.assertEqual(ev, {"zero": 1, "extended": 5}) def test_json_dec_int(self): dec = json_encdec() dv = dec.decode(int(), 1234) self.assertEqual(dv, 1234) dv = dec.decode(int(), "0xAA") self.assertEqual(dv, 0xAA) dv = dec.decode(int(), [1, 2]) self.assertEqual(dv, 0x100000002) def test_json_dec_friendly_int(self): dec = json_encdec() dv = dec.decode(TPM2_ALG(), "sha1") self.assertEqual(dv, TPM2_ALG.SHA1) dv = dec.decode(TPM2_ALG(), "0x4") self.assertEqual(dv, TPM2_ALG.SHA1) dv = dec.decode(TPM2_ALG(), int(TPM2_ALG.SHA1)) self.assertEqual(dv, TPM2_ALG.SHA1) def test_json_dec_friendly_intlist(self): dec = json_encdec() dv = dec.decode( TPMA_OBJECT.RESTRICTED, {"userwithauth": 1, "restricted": 0, "sign_encrypt": 1}, ) self.assertEqual(dv, TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT) dv = dec.decode(TPMA_OBJECT(), ["TPMA_OBJECT_RESTRICTED", "ADMINWITHPOLICY"]) self.assertEqual(dv, TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.ADMINWITHPOLICY) dv = dec.decode( TPMA_OBJECT(), f"0x{TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT:x}" ) self.assertEqual(dv, TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT) dv = dec.decode(TPMA_NV(), {"written": "set", "nt": "counter"}) self.assertEqual(dv, TPMA_NV.WRITTEN | TPM2_NT.COUNTER << TPMA_NV.TPM2_NT_SHIFT) dv = dec.decode(TPMA_CC(), {"v": 1, "commandindex": 1234, "chandles": 5}) self.assertEqual(dv, TPMA_CC.V | 1234 | 5 << TPMA_CC.CHANDLES_SHIFT) dv = dec.decode(TPMA_LOCALITY(), {"one": 1, "extended": 5}) self.assertEqual(dv, TPMA_LOCALITY(0xA0) | TPMA_LOCALITY.ONE) def test_json_dec_simple_tpm2b(self): dec = json_encdec() dv = dec.decode(TPM2B_DIGEST(), "01020304") self.assertEqual(dv, b"\x01\x02\x03\x04") dv = dec.decode(TPM2B_DIGEST(), "0xff") self.assertEqual(dv, b"\xFF") dv = dec.decode(TPM2B_DIGEST(), [1, 2, 3, 4]) self.assertEqual(dv, b"\x01\x02\x03\x04") if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_esapi.py000066400000000000000000005272021506405471500177460ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest import gc import pytest from tpm2_pytss import * from .TSS2_BaseTest import TSS2_EsapiTest from tpm2_pytss.internal.utils import _lib_version_atleast class TestEsys(TSS2_EsapiTest): def test_get_random(self): r = self.ectx.get_random(5) self.assertEqual(len(r), 5) with self.assertRaises(TypeError): self.ectx.get_random("foo") with self.assertRaises(TypeError): self.ectx.get_random(5, session1="baz") with self.assertRaises(TypeError): self.ectx.get_random(5, session2=object()) with self.assertRaises(TypeError): self.ectx.get_random(5, session3=56.7) def test_create_primary(self): inSensitive = TPM2B_SENSITIVE_CREATE() inPublic = TPM2B_PUBLIC() outsideInfo = TPM2B_DATA() creationPCR = TPML_PCR_SELECTION() inPublic.publicArea.type = TPM2_ALG.ECC inPublic.publicArea.nameAlg = TPM2_ALG.SHA1 inPublic.publicArea.objectAttributes = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ) inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = ( TPM2_ALG.SHA256 ) inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.curveID = TPM2_ECC.NIST_P256 handle, public, creation_data, digest, ticket = self.ectx.create_primary( inSensitive, inPublic, ESYS_TR.OWNER, outsideInfo, creationPCR ) self.assertNotEqual(handle, 0) self.assertEqual(type(public), TPM2B_PUBLIC) self.assertEqual(type(creation_data), TPM2B_CREATION_DATA) self.assertEqual(type(digest), TPM2B_DIGEST) self.assertEqual(type(ticket), TPMT_TK_CREATION) self.ectx.flush_context(handle) handle, _, _, _, _ = self.ectx.create_primary(inSensitive) self.assertNotEqual(handle, 0) self.ectx.flush_context(handle) handle, _, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) self.assertNotEqual(handle, 0) self.ectx.flush_context(handle) handle, _, _, _, _ = self.ectx.create_primary(inSensitive, "ecc256") self.assertNotEqual(handle, 0) self.ectx.flush_context(handle) handle, _, _, _, _ = self.ectx.create_primary( inSensitive, "ecc256", creation_pcr="sha256:4,6,7" ) self.assertNotEqual(handle, 0) self.ectx.flush_context(handle) with self.assertRaises(TypeError): self.ectx.create_primary( TPM2B_DATA, inPublic, ESYS_TR.OWNER, outsideInfo, creationPCR ) with self.assertRaises(TypeError): self.ectx.create_primary( inSensitive, b"should not work", ESYS_TR.OWNER, outsideInfo, creationPCR, ) with self.assertRaises(TypeError): self.ectx.create_primary( inSensitive, inPublic, object(), outsideInfo, creationPCR ) with self.assertRaises(TypeError): self.ectx.create_primary( inSensitive, inPublic, ESYS_TR.OWNER, object(), creationPCR ) with self.assertRaises(TypeError): self.ectx.create_primary( inSensitive, inPublic, ESYS_TR.OWNER, outsideInfo, TPM2B_SENSITIVE() ) with self.assertRaises(TypeError): handle, _, _, _, _ = self.ectx.create_primary( inSensitive, "ecc256", session1=object() ) with self.assertRaises(TypeError): handle, _, _, _, _ = self.ectx.create_primary( inSensitive, "ecc256", session2=object() ) with self.assertRaises(TypeError): handle, _, _, _, _ = self.ectx.create_primary( inSensitive, "ecc256", session3=object() ) def test_create_primary_none(self): handle, _, _, _, _ = self.ectx.create_primary(None) self.assertNotEqual(handle, 0) def test_pcr_read(self): pcrsels = TPML_PCR_SELECTION.parse("sha1:3+sha256:all") _, _, digests = self.ectx.pcr_read(pcrsels) self.assertEqual(len(digests[0]), 20) for d in digests[1:]: self.assertEqual(len(d), 32) with self.assertRaises(TypeError): self.ectx.pcr_read(TPML_AC_CAPABILITIES()) with self.assertRaises(TypeError): self.ectx.pcr_read(pcrsels, session1="bar") with self.assertRaises(TypeError): self.ectx.pcr_read(pcrsels, session2=56.7) with self.assertRaises(TypeError): self.ectx.pcr_read(pcrsels, session3=object()) def test_plain_nv_define_write_read_undefine(self): nv_public = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=TPM2_HC.NV_INDEX_FIRST, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.parse("ownerread|ownerwrite|authread|authwrite"), dataSize=32, ) ) # No password NV index nv_index = self.ectx.nv_define_space(None, nv_public) self.ectx.nv_write(nv_index, b"hello world") value = self.ectx.nv_read(nv_index, 11) self.assertEqual(bytes(value), b"hello world") public, name = self.ectx.nv_read_public(nv_index) self.assertEqual(public.nvPublic.nvIndex, TPM2_HC.NV_INDEX_FIRST) self.assertEqual(public.nvPublic.nameAlg, TPM2_ALG.SHA256) self.assertEqual( public.nvPublic.attributes, TPMA_NV.parse("ownerread|ownerwrite|authread|authwrite|written"), ) self.assertEqual(public.nvPublic.authPolicy.size, 0) self.assertEqual(public.nvPublic.dataSize, 32) # Algorithm id (UINT16) followed by SHA256 len of name bytes self.assertEqual(len(name), 2 + 32) n = str(name) self.assertEqual(len(n), 68) self.assertTrue(isinstance(n, str)) self.ectx.nv_undefine_space(nv_index) with self.assertRaises(TSS2_Exception): self.ectx.nv_read_public(nv_index) def test_hierarchychangeauth(self): self.ectx.hierarchy_change_auth(ESYS_TR.OWNER, "passwd") # force esys to forget about the 'good' password self.ectx.tr_set_auth(ESYS_TR.OWNER, "badpasswd") with self.assertRaises(TSS2_Exception): self.ectx.hierarchy_change_auth(ESYS_TR.OWNER, "anotherpasswd") def test_fulltest_yes(self): self.ectx.self_test(True) def test_fulltest_no(self): self.ectx.self_test(False) def test_incremental_self_test(self): algs = TPML_ALG.parse("rsa,ecc,xor,aes,cbc") self.ectx.incremental_self_test(algs) self.ectx.incremental_self_test("rsa,ecc,xor,aes,cbc") with self.assertRaises(TypeError): self.ectx.incremental_self_test(None) with self.assertRaises(TypeError): self.ectx.incremental_self_test(object()) with self.assertRaises(TypeError): self.ectx.incremental_self_test(session1=45.9) with self.assertRaises(TypeError): self.ectx.incremental_self_test(session2=object()) with self.assertRaises(TypeError): self.ectx.incremental_self_test(session3=TPM2B_PUBLIC()) def test_incremental_resume_test(self): algs = TPML_ALG.parse("rsa,ecc,xor,aes,cbc") self.ectx.incremental_self_test(algs) toDo, rc = self.ectx.get_test_result() self.assertEqual(type(toDo), TPM2B_MAX_BUFFER) self.assertEqual(rc, TPM2_RC.SUCCESS) with self.assertRaises(TypeError): self.ectx.get_test_result(session1=45.7) with self.assertRaises(TypeError): self.ectx.get_test_result(session2=TPM2B_DATA()) with self.assertRaises(TypeError): self.ectx.get_test_result(session3=object()) def test_hmac_session(self): sym = TPMT_SYM_DEF( algorithm=TPM2_ALG.XOR, keyBits=TPMU_SYM_KEY_BITS(exclusiveOr=TPM2_ALG.SHA256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) hmac_session = self.ectx.start_auth_session( tpm_key=ESYS_TR.NONE, bind=ESYS_TR.NONE, session_type=TPM2_SE.HMAC, symmetric=sym, auth_hash=TPM2_ALG.SHA256, ) self.assertTrue(hmac_session) self.ectx.hierarchy_change_auth(ESYS_TR.OWNER, "passwd", session1=hmac_session) # force esys to forget about the 'good' password self.ectx.tr_set_auth(ESYS_TR.OWNER, "badpasswd") with self.assertRaises(TSS2_Exception): self.ectx.hierarchy_change_auth( ESYS_TR.OWNER, "anotherpasswd", session1=hmac_session ) # test some bad params with self.assertRaises(TypeError): self.ectx.start_auth_session( object, ESYS_TR.NONE, TPM2_SE.HMAC, sym, TPM2_ALG.SHA256 ) with self.assertRaises(TypeError): self.ectx.start_auth_session( ESYS_TR.NONE, object(), TPM2_SE.HMAC, sym, TPM2_ALG.SHA256 ) with self.assertRaises(ValueError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, 8745635, sym, TPM2_ALG.SHA256 ) with self.assertRaises(TypeError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, object(), sym, TPM2_ALG.SHA256 ) with self.assertRaises(TypeError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.HMAC, 42, TPM2_ALG.SHA256 ) with self.assertRaises(ValueError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.HMAC, sym, 8395847 ) with self.assertRaises(TypeError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.HMAC, sym, TPM2B_SYM_KEY() ) with self.assertRaises(TypeError): self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.HMAC, sym, TPM2_ALG.SHA256, TPM2B_PUBLIC(), ) def test_start_auth_session_enckey(self): inSensitive = TPM2B_SENSITIVE_CREATE() handle, _, _, _, _ = self.ectx.create_primary(inSensitive, "rsa2048:aes128cfb") session = self.ectx.start_auth_session( tpm_key=handle, bind=ESYS_TR.NONE, session_type=TPM2_SE.POLICY, symmetric="aes128cfb", auth_hash="sha256", ) self.ectx.trsess_set_attributes( session, (TPMA_SESSION.ENCRYPT | TPMA_SESSION.DECRYPT) ) random = self.ectx.get_random(4, session1=session) self.assertEqual(len(random), 4) def test_start_auth_session_enckey_bindkey(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) handle, _, _, _, _ = self.ectx.create_primary(inSensitive, "rsa2048:aes128cfb") sym = TPMT_SYM_DEF( algorithm=TPM2_ALG.XOR, keyBits=TPMU_SYM_KEY_BITS(exclusiveOr=TPM2_ALG.SHA256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) session = self.ectx.start_auth_session( tpm_key=handle, bind=handle, session_type=TPM2_SE.POLICY, symmetric=sym, auth_hash=TPM2_ALG.SHA256, ) self.ectx.trsess_set_attributes( session, (TPMA_SESSION.ENCRYPT | TPMA_SESSION.DECRYPT) ) random = self.ectx.get_random(4, session1=session) self.assertEqual(len(random), 4) def test_tr_sess_set_attributes(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) handle, _, _, _, _ = self.ectx.create_primary(inSensitive, "rsa2048:aes128cfb") sym = TPMT_SYM_DEF( algorithm=TPM2_ALG.XOR, keyBits=TPMU_SYM_KEY_BITS(exclusiveOr=TPM2_ALG.SHA256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) session = self.ectx.start_auth_session( tpm_key=handle, bind=handle, session_type=TPM2_SE.POLICY, symmetric=sym, auth_hash=TPM2_ALG.SHA256, ) self.ectx.trsess_set_attributes( session, (TPMA_SESSION.ENCRYPT | TPMA_SESSION.DECRYPT) ) with self.assertRaises(TypeError): self.ectx.trsess_set_attributes( object(), (TPMA_SESSION.ENCRYPT | TPMA_SESSION.DECRYPT) ) with self.assertRaises(TypeError): self.ectx.trsess_set_attributes(session, 67.5) with self.assertRaises(TypeError): self.ectx.trsess_set_attributes(session, 1, 75.6) def test_start_auth_session_noncecaller(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) handle, _, _, _, _ = self.ectx.create_primary(inSensitive, "rsa2048:aes128cfb") sym = TPMT_SYM_DEF( algorithm=TPM2_ALG.XOR, keyBits=TPMU_SYM_KEY_BITS(exclusiveOr=TPM2_ALG.SHA256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) session = self.ectx.start_auth_session( tpm_key=handle, bind=handle, session_type=TPM2_SE.POLICY, symmetric=sym, auth_hash=TPM2_ALG.SHA256, nonce_caller=TPM2B_NONCE(b"thisisthirtytwocharslastichecked"), ) self.ectx.trsess_set_attributes( session, (TPMA_SESSION.ENCRYPT | TPMA_SESSION.DECRYPT) ) random = self.ectx.get_random(4, session1=session) self.assertEqual(len(random), 4) def test_start_auth_session_noncecaller_bad(self): sym = TPMT_SYM_DEF( algorithm=TPM2_ALG.XOR, keyBits=TPMU_SYM_KEY_BITS(exclusiveOr=TPM2_ALG.SHA256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) with self.assertRaises(TypeError): self.ectx.start_auth_session( tpm_key=ESYS_TR.NONE, bind=ESYS_TR.NONE, session_type=TPM2_SE.HMAC, symmetric=sym, auth_hash=TPM2_ALG.SHA256, nonce_caller=object(), ) def test_create(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) alg = "rsa2048" childInPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg)) outsideInfo = TPM2B_DATA() creationPCR = TPML_PCR_SELECTION() priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic, outsideInfo, creationPCR ) self.assertEqual(type(priv), TPM2B_PRIVATE), self.assertEqual(type(pub), TPM2B_PUBLIC), priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic, outsideInfo ) self.assertEqual(type(priv), TPM2B_PRIVATE), self.assertEqual(type(pub), TPM2B_PUBLIC), priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic, creation_pcr=creationPCR ) self.assertEqual(type(priv), TPM2B_PRIVATE), self.assertEqual(type(pub), TPM2B_PUBLIC), priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic, creation_pcr="sha256:1,2,3,4,5", ) self.assertEqual(type(priv), TPM2B_PRIVATE), self.assertEqual(type(pub), TPM2B_PUBLIC), with self.assertRaises(TypeError): self.ectx.create( 34.945, childInSensitive, childInPublic, outsideInfo, creationPCR ) with self.assertRaises(TypeError): self.ectx.create( parentHandle, object(), childInPublic, outsideInfo, creationPCR ) with self.assertRaises(TypeError): self.ectx.create( parentHandle, childInSensitive, 56, outsideInfo, creationPCR ) with self.assertRaises(TypeError): self.ectx.create( parentHandle, childInSensitive, childInPublic, None, creationPCR ) with self.assertRaises(TypeError): self.ectx.create( parentHandle, childInSensitive, childInPublic, outsideInfo, object ) def test_create_none(self): parentHandle = self.ectx.create_primary(None)[0] priv, pub = self.ectx.create(parentHandle, None)[0:2] self.assertEqual(type(pub), TPM2B_PUBLIC) self.assertEqual(type(priv), TPM2B_PRIVATE) def test_load(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) priv, pub, _, _, _ = self.ectx.create(parentHandle, childInSensitive) childHandle = self.ectx.load(parentHandle, priv, pub) self.assertTrue(childHandle) with self.assertRaises(TypeError): self.ectx.load(42.5, priv, pub) with self.assertRaises(TypeError): self.ectx.load(parentHandle, TPM2B_DATA(), pub) with self.assertRaises(TypeError): self.ectx.load(parentHandle, priv, object()) def test_readpublic(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) priv, pub, _, _, _ = self.ectx.create(parentHandle, childInSensitive) childHandle = self.ectx.load(parentHandle, priv, pub) pubdata, name, qname = self.ectx.read_public(childHandle) self.assertTrue( isinstance(pubdata, TPM2B_PUBLIC), f"Expected TPM2B_PUBLIC, got: {type(pubdata)}", ) self.assertTrue( isinstance(name, TPM2B_NAME), f"Expected TPM2B_NAME, got: {type(name)}" ) self.assertTrue( isinstance(qname, TPM2B_NAME), f"Expected TPM2B_NAME, got: {type(qname)}" ) self.assertTrue(pubdata.publicArea.type, TPM2_ALG.RSA) self.assertTrue(pubdata.publicArea.nameAlg, TPM2_ALG.SHA256) self.assertTrue(name.size, 32) self.assertTrue(qname.size, 32) with self.assertRaises(TypeError): self.ectx.read_public(object()) with self.assertRaises(TypeError): self.ectx.read_public(childHandle, session1=object) with self.assertRaises(TypeError): self.ectx.read_public(childHandle, session2="foo") with self.assertRaises(TypeError): self.ectx.read_public(childHandle, session3=42.5) def test_make_credential(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) alg = "rsa2048" attrs = ( TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ) childInPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg=alg, objectAttributes=attrs)) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic ) childHandle = self.ectx.load(parentHandle, priv, pub) primaryKeyName = self.ectx.read_public(parentHandle)[1] credential = TPM2B_DIGEST("this is my credential") # this can be done without a key as in tpm2-tools project, but for simpplicity # use the TPM command, which uses the PUBLIC portion of the object and thus # needs no auth. credentialBlob, secret = self.ectx.make_credential( childHandle, credential, primaryKeyName ) self.assertEqual(type(credentialBlob), TPM2B_ID_OBJECT) self.assertEqual(type(secret), TPM2B_ENCRYPTED_SECRET) credentialBlob, secret = self.ectx.make_credential( childHandle, "this is my credential", bytes(primaryKeyName) ) self.assertEqual(type(credentialBlob), TPM2B_ID_OBJECT) self.assertEqual(type(secret), TPM2B_ENCRYPTED_SECRET) with self.assertRaises(TypeError): self.ectx.make_credential(42.5, credential, primaryKeyName) with self.assertRaises(TypeError): self.ectx.make_credential(childHandle, object(), primaryKeyName) with self.assertRaises(TypeError): self.ectx.make_credential(childHandle, credential, object()) with self.assertRaises(TypeError): self.ectx.make_credential( childHandle, credential, primaryKeyName, session1="bar" ) with self.assertRaises(TypeError): self.ectx.make_credential( childHandle, credential, primaryKeyName, session2=54.6 ) with self.assertRaises(TypeError): self.ectx.make_credential( childHandle, credential, primaryKeyName, session3=object() ) def test_activate_credential(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) alg = "rsa2048" attrs = ( TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ) childInPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg=alg, objectAttributes=attrs)) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic ) childHandle = self.ectx.load(parentHandle, priv, pub) primaryKeyName = self.ectx.read_public(parentHandle)[1] credential = TPM2B_DIGEST("this is my credential") # this can be done without a key as in tpm2-tools project, but for simpplicity # use the TPM command, which uses the PUBLIC portion of the object and thus # needs no auth. credentialBlob, secret = self.ectx.make_credential( childHandle, credential, primaryKeyName ) self.ectx.tr_set_auth(childHandle, "childpassword") certInfo = self.ectx.activate_credential( parentHandle, childHandle, credentialBlob, secret ) self.assertEqual(bytes(certInfo), b"this is my credential") with self.assertRaises(TypeError): self.ectx.activate_credential(object(), childHandle, credentialBlob, secret) with self.assertRaises(TypeError): self.ectx.activate_credential(parentHandle, 76.4, credentialBlob, secret) with self.assertRaises(TypeError): self.ectx.activate_credential( parentHandle, childHandle, TPM2B_PUBLIC(), secret ) with self.assertRaises(TypeError): self.ectx.activate_credential( parentHandle, childHandle, credentialBlob, object() ) with self.assertRaises(TypeError): self.ectx.activate_credential( parentHandle, childHandle, credentialBlob, secret, session1="foo" ) with self.assertRaises(TypeError): self.ectx.activate_credential( parentHandle, childHandle, credentialBlob, secret, session2=object() ) with self.assertRaises(TypeError): self.ectx.activate_credential( parentHandle, childHandle, credentialBlob, secret, session3=65.4 ) def test_unseal(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) attrs = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.FIXEDTPM ) templ = TPMT_PUBLIC( type=TPM2_ALG.KEYEDHASH, objectAttributes=attrs, nameAlg=TPM2_ALG.SHA256 ) templ.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG.NULL templ.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = TPM2_ALG.SHA256 childInPublic = TPM2B_PUBLIC(templ) childInSensitive = TPM2B_SENSITIVE_CREATE( # TODO make sure this works without the buffer, and for other SIMPLE TPM2B types TPMS_SENSITIVE_CREATE( userAuth=TPM2B_AUTH("childpassword"), data=TPM2B_SENSITIVE_DATA(b"sealedsecret"), ) ) priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic ) childHandle = self.ectx.load(parentHandle, priv, pub) self.ectx.tr_set_auth(childHandle, "childpassword") secret = self.ectx.unseal(childHandle) self.assertEqual(bytes(secret), b"sealedsecret") with self.assertRaises(TypeError): self.ectx.unseal(45.2) with self.assertRaises(TypeError): self.ectx.unseal(childHandle, session1=object()) with self.assertRaises(TypeError): self.ectx.unseal(childHandle, session2=67.4) with self.assertRaises(TypeError): self.ectx.unseal(childHandle, session3="bar") def test_object_change_auth(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) alg = "rsa2048" attrs = ( TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ) childInPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg=alg, objectAttributes=attrs)) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) priv, pub, _, _, _ = self.ectx.create( parentHandle, childInSensitive, childInPublic ) childHandle = self.ectx.load(parentHandle, priv, pub) # force an error self.ectx.tr_set_auth(childHandle, "BADchildpassword") with self.assertRaises(TSS2_Exception): self.ectx.object_change_auth(childHandle, parentHandle, "newauth") self.ectx.tr_set_auth(childHandle, "childpassword") self.ectx.object_change_auth(childHandle, parentHandle, TPM2B_AUTH("newauth")) self.ectx.object_change_auth(childHandle, parentHandle, b"anotherauth") self.ectx.object_change_auth(childHandle, parentHandle, "yetanotherone") with self.assertRaises(TypeError): self.ectx.object_change_auth("bad", parentHandle, "yetanotherone") with self.assertRaises(TypeError): self.ectx.object_change_auth(childHandle, 56.7, "yetanotherone") with self.assertRaises(TypeError): self.ectx.object_change_auth(childHandle, parentHandle, object()) def test_createloaded(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) templ = TPMT_PUBLIC.parse( alg="rsa2048", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) childInPublic = TPM2B_TEMPLATE(templ.marshal()) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) childHandle, priv, pub = self.ectx.create_loaded( parentHandle, childInSensitive, childInPublic ) self.assertNotEqual(childHandle, 0) self.assertEqual(type(priv), TPM2B_PRIVATE) self.assertEqual(type(pub), TPM2B_PUBLIC) childHandle, priv, pub = self.ectx.create_loaded(parentHandle, childInSensitive) self.assertNotEqual(childHandle, 0) self.assertEqual(type(priv), TPM2B_PRIVATE) self.assertEqual(type(pub), TPM2B_PUBLIC) with self.assertRaises(TypeError): self.ectx.create_loaded(65.4, childInSensitive, childInPublic) with self.assertRaises(TypeError): self.ectx.create_loaded(parentHandle, "1223", childInPublic) with self.assertRaises(TypeError): self.ectx.create_loaded(parentHandle, childInSensitive, object()) with self.assertRaises(TypeError): self.ectx.create_loaded(parentHandle, childInSensitive, session1=56.7) with self.assertRaises(TypeError): self.ectx.create_loaded(parentHandle, childInSensitive, session2=b"baz") with self.assertRaises(TypeError): self.ectx.create_loaded(parentHandle, childInSensitive, session3=object()) def test_createloaded_none(self): parentHandle = self.ectx.create_primary(None)[0] childHandle = self.ectx.create_loaded(parentHandle, None)[0] self.assertNotEqual(childHandle, 0) def test_rsa_enc_dec(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) templ = TPMT_PUBLIC.parse( alg="rsa2048", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) childInPublic = TPM2B_TEMPLATE(templ.marshal()) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) childHandle, _, _ = self.ectx.create_loaded( parentHandle, childInSensitive, childInPublic ) message = TPM2B_PUBLIC_KEY_RSA("hello world") scheme = TPMT_RSA_DECRYPT(scheme=TPM2_ALG.RSAES) outData = self.ectx.rsa_encrypt(childHandle, message, scheme) message2 = self.ectx.rsa_decrypt(childHandle, outData, scheme) self.assertEqual(bytes(message), bytes(message2)) outData = self.ectx.rsa_encrypt(childHandle, "hello world", scheme) message2 = self.ectx.rsa_decrypt(childHandle, outData, scheme) self.assertEqual(bytes(message), bytes(message2)) # negative test rsa_encrypt with self.assertRaises(TypeError): self.ectx.rsa_encrypt(45.6, message, scheme) with self.assertRaises(TypeError): self.ectx.rsa_encrypt(childHandle, TPM2B_PUBLIC(), scheme) with self.assertRaises(TypeError): self.ectx.rsa_encrypt(childHandle, message, "foo") with self.assertRaises(TypeError): self.ectx.rsa_encrypt(childHandle, message, scheme, session1=object()) with self.assertRaises(TypeError): self.ectx.rsa_encrypt(childHandle, message, scheme, session2="foo") with self.assertRaises(TypeError): self.ectx.rsa_encrypt(childHandle, message, scheme, session3=52.6) # negative test rsa_decrypt with self.assertRaises(TypeError): self.ectx.rsa_decrypt(56.2, outData, scheme) with self.assertRaises(TypeError): self.ectx.rsa_decrypt(childHandle, object(), scheme) with self.assertRaises(TypeError): self.ectx.rsa_decrypt(childHandle, outData, TPM2_ALG.RSAES) with self.assertRaises(TypeError): self.ectx.rsa_decrypt(childHandle, outData, scheme, session1=67.9) with self.assertRaises(TypeError): self.ectx.rsa_decrypt(childHandle, outData, scheme, session2="foo") with self.assertRaises(TypeError): self.ectx.rsa_decrypt(childHandle, outData, scheme, session3=object()) def test_rsa_enc_dec_with_label(self): inSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("password")) ) parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "rsa2048:aes128cfb" ) templ = TPMT_PUBLIC.parse( alg="rsa2048", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) childInPublic = TPM2B_TEMPLATE(templ.marshal()) childInSensitive = TPM2B_SENSITIVE_CREATE( TPMS_SENSITIVE_CREATE(userAuth=TPM2B_AUTH("childpassword")) ) childHandle, _, _ = self.ectx.create_loaded( parentHandle, childInSensitive, childInPublic ) message = TPM2B_PUBLIC_KEY_RSA("hello world") scheme = TPMT_RSA_DECRYPT(scheme=TPM2_ALG.RSAES) outData = self.ectx.rsa_encrypt( childHandle, message, scheme, label=b"my label\0" ) message2 = self.ectx.rsa_decrypt( childHandle, outData, scheme, label=b"my label\0" ) self.assertEqual(bytes(message), bytes(message2)) def test_ecdh_key_gen(self): inSensitive = TPM2B_SENSITIVE_CREATE() parentHandle, _, _, _, _ = self.ectx.create_primary( inSensitive, "ecc256:aes128cfb" ) zPoint, pubPoint = self.ectx.ecdh_key_gen(parentHandle) self.assertNotEqual(zPoint, None) self.assertNotEqual(pubPoint, None) with self.assertRaises(TypeError): self.ectx.ecdh_key_gen(56.8) with self.assertRaises(TypeError): self.ectx.ecdh_key_gen(parentHandle, session1="baz") with self.assertRaises(TypeError): self.ectx.ecdh_key_gen(parentHandle, session2=object()) with self.assertRaises(TypeError): self.ectx.ecdh_key_gen(parentHandle, session3=45.6) def test_ecdh_z_gen(self): alg = "ecc256:ecdh" attrs = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ) inPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg=alg, objectAttributes=attrs)) inSensitive = TPM2B_SENSITIVE_CREATE(TPMS_SENSITIVE_CREATE()) parentHandle, _, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) inPoint = TPM2B_ECC_POINT( TPMS_ECC_POINT( x=binascii.unhexlify( "25db1f8bbcfabc31f8176acbb2f840a3b6a5d340659d37eed9fd5247f514d598" ), y=binascii.unhexlify( "ed623e3dd20908cf583c814bbf657e08ab9f40ffea51da21298ce24deb344ccc" ), ) ) outPoint = self.ectx.ecdh_zgen(parentHandle, inPoint) self.assertEqual(type(outPoint), TPM2B_ECC_POINT) with self.assertRaises(TypeError): self.ectx.ecdh_zgen(object(), inPoint) with self.assertRaises(TypeError): self.ectx.ecdh_zgen(parentHandle, "boo") with self.assertRaises(TypeError): self.ectx.ecdh_zgen(parentHandle, inPoint, session1="baz") with self.assertRaises(TypeError): self.ectx.ecdh_zgen(parentHandle, inPoint, session2=object()) with self.assertRaises(TypeError): self.ectx.ecdh_zgen(parentHandle, inPoint, session3=89.6) def test_ecc_parameters(self): params = self.ectx.ecc_parameters(TPM2_ECC_CURVE.NIST_P256) self.assertEqual(type(params), TPMS_ALGORITHM_DETAIL_ECC) with self.assertRaises(ValueError): self.ectx.ecc_parameters(42) with self.assertRaises(TypeError): self.ectx.ecc_parameters(TPM2B_DATA()) with self.assertRaises(TypeError): self.ectx.ecc_parameters(TPM2_ECC_CURVE.NIST_P256, session1="foo") with self.assertRaises(TypeError): self.ectx.ecc_parameters(TPM2_ECC_CURVE.NIST_P256, session2=object()) with self.assertRaises(TypeError): self.ectx.ecc_parameters(TPM2_ECC_CURVE.NIST_P256, session3=TPM2B_DATA()) def test_z_gen_2_phase(self): alg = "ecc256:ecdh-sha256" attrs = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.DECRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ) inPublic = TPM2B_PUBLIC(TPMT_PUBLIC.parse(alg=alg, objectAttributes=attrs)) inSensitive = TPM2B_SENSITIVE_CREATE(TPMS_SENSITIVE_CREATE()) eccHandle, outPublic, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) curveId = TPM2_ECC.NIST_P256 Q, counter = self.ectx.ec_ephemeral(curveId) inQsB = TPM2B_ECC_POINT(outPublic.publicArea.unique.ecc) inQeB = Q Z1, Z2 = self.ectx.zgen_2_phase(eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, counter) self.assertEqual(type(Z1), TPM2B_ECC_POINT) self.assertEqual(type(Z2), TPM2B_ECC_POINT) with self.assertRaises(TypeError): self.ectx.zgen_2_phase(42.5, inQsB, inQeB, TPM2_ALG.ECDH, counter) with self.assertRaises(TypeError): self.ectx.zgen_2_phase(eccHandle, "hello", inQeB, TPM2_ALG.ECDH, counter) with self.assertRaises(TypeError): self.ectx.zgen_2_phase(eccHandle, inQsB, object(), TPM2_ALG.ECDH, counter) with self.assertRaises(TypeError): self.ectx.zgen_2_phase(eccHandle, inQsB, inQeB, object(), counter) with self.assertRaises(TypeError): self.ectx.zgen_2_phase(eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, "baz") with self.assertRaises(ValueError): self.ectx.zgen_2_phase(eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, 2**18) with self.assertRaises(TypeError): self.ectx.zgen_2_phase( eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, counter, session1=object() ) with self.assertRaises(TypeError): self.ectx.zgen_2_phase( eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, counter, session2="baz" ) with self.assertRaises(TypeError): self.ectx.zgen_2_phase( eccHandle, inQsB, inQeB, TPM2_ALG.ECDH, counter, session3=45.5 ) def test_encrypt_decrypt(self): inSensitive = TPM2B_SENSITIVE_CREATE() parentHandle = self.ectx.create_primary(inSensitive, "ecc")[0] inPublic = TPM2B_TEMPLATE(TPMT_PUBLIC.parse(alg="aes").marshal()) aesKeyHandle = self.ectx.create_loaded(parentHandle, inSensitive, inPublic)[0] ivIn = TPM2B_IV(b"thisis16byteszxc") inData = TPM2B_MAX_BUFFER(b"this is data to encrypt") outCipherText, outIV = self.ectx.encrypt_decrypt( aesKeyHandle, False, TPM2_ALG.CFB, ivIn, inData ) self.assertEqual(len(outIV), len(ivIn)) outData, outIV2 = self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText ) self.assertEqual(bytes(inData), bytes(outData)) self.assertEqual(bytes(outIV), bytes(outIV2)) # test plain bytes for data ivIn = b"thisis16byteszxc" inData = b"this is data to encrypt" outCipherText, outIV = self.ectx.encrypt_decrypt( aesKeyHandle, False, TPM2_ALG.CFB, ivIn, inData ) self.assertEqual(len(outIV), len(ivIn)) outData, outIV2 = self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText ) self.assertEqual(inData, bytes(outData)) self.assertEqual(bytes(outIV), bytes(outIV2)) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(42.5, True, TPM2_ALG.CFB, ivIn, outCipherText) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, object(), TPM2_ALG.CFB, ivIn, outCipherText ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(aesKeyHandle, True, object(), ivIn, outCipherText) with self.assertRaises(ValueError): self.ectx.encrypt_decrypt(aesKeyHandle, True, 42, ivIn, outCipherText) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, TPM2B_PUBLIC(), outCipherText ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(aesKeyHandle, True, TPM2_ALG.CFB, ivIn, None) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session1=object() ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session2="foo" ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session3=12.3 ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, "bad Bool", TPM2_ALG.CFB, ivIn, inData ) def test_encrypt_decrypt2(self): inSensitive = TPM2B_SENSITIVE_CREATE() parentHandle = self.ectx.create_primary(inSensitive, "ecc")[0] inPublic = TPM2B_TEMPLATE(TPMT_PUBLIC.parse(alg="aes").marshal()) aesKeyHandle = self.ectx.create_loaded(parentHandle, inSensitive, inPublic)[0] ivIn = TPM2B_IV(b"thisis16byteszxc") inData = TPM2B_MAX_BUFFER(b"this is data to encrypt") outCipherText, outIV = self.ectx.encrypt_decrypt_2( aesKeyHandle, False, TPM2_ALG.CFB, ivIn, inData ) self.assertEqual(len(outIV), len(ivIn)) outData, outIV2 = self.ectx.encrypt_decrypt_2( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText ) self.assertEqual(bytes(inData), bytes(outData)) self.assertEqual(bytes(outIV), bytes(outIV2)) ivIn = b"thisis16byteszxc" inData = b"this is data to encrypt" outCipherText, outIV = self.ectx.encrypt_decrypt_2( aesKeyHandle, False, TPM2_ALG.CFB, ivIn, inData ) self.assertEqual(len(outIV), len(ivIn)) outData, outIV2 = self.ectx.encrypt_decrypt_2( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText ) self.assertEqual(inData, bytes(outData)) self.assertEqual(bytes(outIV), bytes(outIV2)) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(42.5, True, TPM2_ALG.CFB, ivIn, outCipherText) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, object(), TPM2_ALG.CFB, ivIn, outCipherText ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(aesKeyHandle, True, object(), ivIn, outCipherText) with self.assertRaises(ValueError): self.ectx.encrypt_decrypt(aesKeyHandle, True, 42, ivIn, outCipherText) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, TPM2B_PUBLIC(), outCipherText ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt(aesKeyHandle, True, TPM2_ALG.CFB, ivIn, None) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session1=object() ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session2="foo" ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt( aesKeyHandle, True, TPM2_ALG.CFB, ivIn, outCipherText, session3=12.3 ) with self.assertRaises(TypeError): self.ectx.encrypt_decrypt_2( aesKeyHandle, "Not Bool", TPM2_ALG.CFB, ivIn, inData ) def test_hash(self): # Null hierarchy default digest, ticket = self.ectx.hash(b"1234", TPM2_ALG.SHA256) self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) d = bytes(digest) c = binascii.unhexlify( "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4" ) self.assertEqual(c, d) # Owner hierarchy set digest, ticket = self.ectx.hash(b"1234", TPM2_ALG.SHA256, ESYS_TR.OWNER) self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) d = bytes(digest) c = binascii.unhexlify( "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4" ) self.assertEqual(c, d) # Test TPM2B_MAX_BUFFER inData = TPM2B_MAX_BUFFER(b"1234") digest, ticket = self.ectx.hash(inData, TPM2_ALG.SHA256) self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) d = bytes(digest) c = binascii.unhexlify( "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4" ) self.assertEqual(c, d) # Test str input inData = TPM2B_MAX_BUFFER("1234") digest, ticket = self.ectx.hash(inData, TPM2_ALG.SHA256) self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) d = bytes(digest) c = binascii.unhexlify( "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4" ) self.assertEqual(c, d) with self.assertRaises(TypeError): self.ectx.hash(object(), TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hash(inData, "baz") with self.assertRaises(ValueError): self.ectx.hash(inData, 42) with self.assertRaises(TypeError): self.ectx.hash(inData, TPM2_ALG.SHA256, session1=56.7) with self.assertRaises(TypeError): self.ectx.hash(inData, TPM2_ALG.SHA256, session2="baz") with self.assertRaises(TypeError): self.ectx.hash(inData, TPM2_ALG.SHA256, session3=object()) def test_hmac(self): attrs = ( TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ) templ = TPMT_PUBLIC.parse(alg="hmac", objectAttributes=attrs) inPublic = TPM2B_PUBLIC(templ) inSensitive = TPM2B_SENSITIVE_CREATE(TPMS_SENSITIVE_CREATE()) primaryHandle = self.ectx.create_primary(inSensitive, inPublic)[0] # Test bytes hmac = self.ectx.hmac(primaryHandle, b"1234", TPM2_ALG.SHA256) self.assertNotEqual(hmac, None) self.assertEqual(len(bytes(hmac)), 32) # Test str hmac = self.ectx.hmac(primaryHandle, "1234", TPM2_ALG.SHA256) self.assertNotEqual(hmac, None) self.assertEqual(len(bytes(hmac)), 32) # Test Native inData = TPM2B_MAX_BUFFER("1234") hmac = self.ectx.hmac(primaryHandle, inData, TPM2_ALG.SHA256) self.assertNotEqual(hmac, None) self.assertEqual(len(bytes(hmac)), 32) with self.assertRaises(TypeError): self.ectx.hmac(45.6, inData, TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hmac(primaryHandle, object(), TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hmac(primaryHandle, inData, "baz") with self.assertRaises(ValueError): self.ectx.hmac(primaryHandle, inData, 42) with self.assertRaises(TypeError): self.ectx.hmac(primaryHandle, inData, TPM2_ALG.SHA256, session1=object()) with self.assertRaises(TypeError): self.ectx.hmac(primaryHandle, inData, TPM2_ALG.SHA256, session2="object") with self.assertRaises(TypeError): self.ectx.hmac(primaryHandle, inData, TPM2_ALG.SHA256, session3=45.6) @pytest.mark.skipif( not _lib_version_atleast("tss2-esapi", "4.0.0"), reason="Attached Components not supported prior to tss v4", ) def test_mac(self): attrs = ( TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ) templ = TPMT_PUBLIC.parse(alg="hmac", objectAttributes=attrs) inPublic = TPM2B_PUBLIC(templ) inSensitive = TPM2B_SENSITIVE_CREATE(TPMS_SENSITIVE_CREATE()) primaryHandle = self.ectx.create_primary(inSensitive, inPublic)[0] # Test for tss v < 3.2.0-167-gc17e3989 if not _lib_version_atleast("tss2-esapi", "4.0.0"): with self.assertRaises(NotImplementedError): self.ectx.mac(primaryHandle, b"1234", TPM2_ALG.SHA256) return # Test bytes mac = self.ectx.mac(primaryHandle, b"1234", TPM2_ALG.SHA256) self.assertNotEqual(mac, None) self.assertEqual(len(bytes(mac)), 32) # Test str mac = self.ectx.mac(primaryHandle, "1234", TPM2_ALG.SHA256) self.assertNotEqual(mac, None) self.assertEqual(len(bytes(mac)), 32) # Test Native inData = TPM2B_MAX_BUFFER("1234") mac = self.ectx.mac(primaryHandle, inData, TPM2_ALG.SHA256) self.assertNotEqual(mac, None) self.assertEqual(len(bytes(mac)), 32) with self.assertRaises(TypeError): self.ectx.mac(45.6, inData, TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.mac(primaryHandle, object(), TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.mac(primaryHandle, inData, "baz") with self.assertRaises(ValueError): self.ectx.mac(primaryHandle, inData, 42) with self.assertRaises(TypeError): self.ectx.mac(primaryHandle, inData, TPM2_ALG.SHA256, session1=object()) with self.assertRaises(TypeError): self.ectx.mac(primaryHandle, inData, TPM2_ALG.SHA256, session2="object") with self.assertRaises(TypeError): self.ectx.mac(primaryHandle, inData, TPM2_ALG.SHA256, session3=45.6) def test_stir_random(self): self.ectx.stir_random(b"1234") self.ectx.stir_random("1234") self.ectx.stir_random(TPM2B_SENSITIVE_DATA("1234")) with self.assertRaises(TypeError): self.ectx.stir_random(object()) with self.assertRaises(TypeError): self.ectx.stir_random("1234", session1=56.7) with self.assertRaises(TypeError): self.ectx.stir_random("1234", session2="foo") with self.assertRaises(TypeError): self.ectx.stir_random("1234", session3=object()) def test_hmac_sequence(self): inPublic = TPM2B_PUBLIC( TPMT_PUBLIC.parse( alg="hmac", objectAttributes=( TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) ) inSensitive = TPM2B_SENSITIVE_CREATE(TPMS_SENSITIVE_CREATE()) handle = self.ectx.create_primary(inSensitive, inPublic)[0] seqHandle = self.ectx.hmac_start(handle, None, TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hmac_start(handle, b"1234", TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hmac_start(handle, "1234", TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hmac_start(handle, TPM2B_AUTH(b"1234"), TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) # self.ectx.tr_set_auth(seqHandle, b"1234") self.ectx.sequence_update(seqHandle, "here is some data") self.ectx.sequence_update(seqHandle, b"more data but byte string") self.ectx.sequence_update(seqHandle, TPM2B_MAX_BUFFER("native data format")) self.ectx.sequence_update(seqHandle, None) digest, ticket = self.ectx.sequence_complete(seqHandle, None) self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) self.assertEqual(len(digest), 32) with self.assertRaises(TypeError): self.ectx.hmac_start(45.6, "1234", TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hmac_start(handle, dict(), TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hmac_start(handle, "1234", object()) with self.assertRaises(ValueError): self.ectx.hmac_start(handle, "1234", 42) with self.assertRaises(TypeError): self.ectx.hmac_start(handle, "1234", TPM2_ALG.SHA256, session1="baz") with self.assertRaises(TypeError): self.ectx.hmac_start(handle, "1234", TPM2_ALG.SHA256, session2=object()) with self.assertRaises(TypeError): self.ectx.hmac_start(handle, "1234", TPM2_ALG.SHA256, session3=45.6) def test_hash_sequence(self): seqHandle = self.ectx.hash_sequence_start(None, TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hash_sequence_start(b"1234", TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hash_sequence_start("1234", TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.flush_context(seqHandle) seqHandle = self.ectx.hash_sequence_start(TPM2B_AUTH(b"1234"), TPM2_ALG.SHA256) self.assertNotEqual(seqHandle, 0) self.ectx.tr_set_auth(seqHandle, b"1234") self.ectx.sequence_update(seqHandle, "here is some data") self.ectx.sequence_update(seqHandle, b"more data but byte string") self.ectx.sequence_update(seqHandle, TPM2B_MAX_BUFFER("native data format")) self.ectx.sequence_update(seqHandle, None) digest, ticket = self.ectx.sequence_complete(seqHandle, "AnotherBuffer") self.assertNotEqual(digest, None) self.assertNotEqual(ticket, None) e = binascii.unhexlify( "a02271d78e351c6e9e775b0570b440d3ac37ad6c02a3b69df940f3f893f80d41" ) d = bytes(digest) self.assertEqual(e, d) with self.assertRaises(TypeError): self.ectx.hash_sequence_start(object(), TPM2_ALG.SHA256) with self.assertRaises(TypeError): self.ectx.hash_sequence_start(b"1234", "dssdf") with self.assertRaises(ValueError): self.ectx.hash_sequence_start(b"1234", 42) with self.assertRaises(TypeError): self.ectx.hash_sequence_start(b"1234", TPM2_ALG.SHA256, session1="baz") with self.assertRaises(TypeError): self.ectx.hash_sequence_start(b"1234", TPM2_ALG.SHA256, session2=56.7) with self.assertRaises(TypeError): self.ectx.hash_sequence_start( b"1234", TPM2_ALG.SHA256, session3=TPM2B_DATA() ) with self.assertRaises(TypeError): self.ectx.sequence_update(56.7, "here is some data") with self.assertRaises(TypeError): self.ectx.sequence_update(seqHandle, []) with self.assertRaises(TypeError): self.ectx.sequence_update(seqHandle, "here is some data", sequence1="foo") with self.assertRaises(TypeError): self.ectx.sequence_update( seqHandle, "here is some data", sequence2=object() ) with self.assertRaises(TypeError): self.ectx.sequence_update(seqHandle, "here is some data", sequence3=78.23) with self.assertRaises(TypeError): self.ectx.sequence_complete(78.25, "AnotherBuffer") with self.assertRaises(TypeError): self.ectx.sequence_complete(seqHandle, []) with self.assertRaises(TypeError): self.ectx.sequence_complete(seqHandle, "AnotherBuffer", hierarchy=object()) with self.assertRaises(ValueError): self.ectx.sequence_complete(seqHandle, "AnotherBuffer", hierarchy=42) with self.assertRaises(TypeError): self.ectx.sequence_complete(seqHandle, "AnotherBuffer", session1=42.67) with self.assertRaises(TypeError): self.ectx.sequence_complete(seqHandle, "AnotherBuffer", session2="baz") with self.assertRaises(TypeError): self.ectx.sequence_complete(seqHandle, "AnotherBuffer", session3=object()) def test_event_sequence_complete(self): seqHandle = self.ectx.hash_sequence_start(TPM2B_AUTH(b"1234"), TPM2_ALG.NULL) self.assertNotEqual(seqHandle, 0) self.ectx.tr_set_auth(seqHandle, b"1234") self.ectx.sequence_update(seqHandle, "here is some data") self.ectx.sequence_update(seqHandle, b"more data but byte string") self.ectx.sequence_update(seqHandle, TPM2B_MAX_BUFFER("native data format")) self.ectx.sequence_update(seqHandle, None) pcrs = self.ectx.event_sequence_complete( ESYS_TR.PCR16, seqHandle, "AnotherBuffer" ) self.assertEqual(type(pcrs), TPML_DIGEST_VALUES) with self.assertRaises(TypeError): self.ectx.event_sequence_complete(object(), seqHandle, None) with self.assertRaises(ValueError): self.ectx.event_sequence_complete(42, seqHandle, None) with self.assertRaises(TypeError): self.ectx.event_sequence_complete(ESYS_TR.PCR16, 46.5, None) with self.assertRaises(TypeError): self.ectx.event_sequence_complete(ESYS_TR.PCR16, seqHandle, object()) with self.assertRaises(TypeError): self.ectx.event_sequence_complete( ESYS_TR.PCR16, seqHandle, None, sequence1=67.34 ) with self.assertRaises(TypeError): self.ectx.event_sequence_complete( ESYS_TR.PCR16, seqHandle, None, sequence2="boo" ) with self.assertRaises(TypeError): self.ectx.event_sequence_complete( ESYS_TR.PCR16, seqHandle, None, sequence3=object() ) def test_context_save_context_load(self): inPublic = TPM2B_PUBLIC( TPMT_PUBLIC.parse( alg="rsa:rsassa-sha256", objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, ) ) inSensitive = TPM2B_SENSITIVE_CREATE() handle, outpub, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) ctx = self.ectx.context_save(handle) nhandle = self.ectx.context_load(ctx) name = self.ectx.tr_get_name(nhandle) self.assertEqual(bytes(outpub.get_name()), bytes(name)) def test_flush_context(self): inPublic = TPM2B_PUBLIC( TPMT_PUBLIC.parse( alg="rsa:rsassa-sha256", objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, ) ) inSensitive = TPM2B_SENSITIVE_CREATE() handle, _, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) self.ectx.flush_context(handle) with self.assertRaises(TSS2_Exception) as e: self.ectx.tr_get_name(handle) self.assertEqual(e.exception.error, TSS2_RC.ESYS_RC_BAD_TR) def test_evict_control(self): inPublic = TPM2B_PUBLIC( TPMT_PUBLIC.parse( alg="rsa:rsassa-sha256", objectAttributes=TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN, ) ) inSensitive = TPM2B_SENSITIVE_CREATE() handle, _, _, _, _ = self.ectx.create_primary(inSensitive, inPublic) self.ectx.evict_control( ESYS_TR.OWNER, handle, 0x81000081, session1=ESYS_TR.PASSWORD ) phandle = self.ectx.tr_from_tpmpublic(0x81000081) self.ectx.evict_control( ESYS_TR.OWNER, phandle, 0x81000081, session1=ESYS_TR.PASSWORD ) with self.assertRaises(TSS2_Exception) as e: self.ectx.tr_from_tpmpublic(0x81000081) self.assertEqual(e.exception.error, TPM2_RC.HANDLE) def test_get_capability(self): more = True while more: more, capdata = self.ectx.get_capability( TPM2_CAP.COMMANDS, TPM2_CC.FIRST, TPM2_MAX.CAP_CC ) for c in capdata.data.command: pass with self.assertRaises(TypeError): self.ectx.get_capability("Not valid", TPM2_CC.FIRST, TPM2_MAX.CAP_CC) with self.assertRaises(TypeError): self.ectx.get_capability(TPM2_CAP.COMMANDS, 45.6, TPM2_MAX.CAP_CC) with self.assertRaises(TypeError): self.ectx.get_capability(TPM2_CAP.COMMANDS, TPM2_CC.FIRST, []) with self.assertRaises(TypeError): self.ectx.get_capability( TPM2_CAP.COMMANDS, TPM2_CC.FIRST, TPM2_MAX.CAP_CC, session1=56.7 ) with self.assertRaises(TypeError): self.ectx.get_capability( TPM2_CAP.COMMANDS, TPM2_CC.FIRST, TPM2_MAX.CAP_CC, session2=object() ) with self.assertRaises(TypeError): self.ectx.get_capability( TPM2_CAP.COMMANDS, TPM2_CC.FIRST, TPM2_MAX.CAP_CC, session3="baz" ) @pytest.mark.skipif( not _lib_version_atleast("tss2-esapi", "4.0.0"), reason="Attached Components not supported prior to tss v4", ) def test_ac_get_capability(self): with self.assertRaisesRegex(TSS2_Exception, "command code not supported"): self.ectx.ac_get_capability(ESYS_TR.NONE, TPM_AT.ANY, 0) @pytest.mark.skipif( not _lib_version_atleast("tss2-esapi", "4.0.0"), reason="Attached Components not supported prior to tss v4", ) def test_ac_send(self): inData = TPM2B_MAX_BUFFER(b"this is data to encrypt") with self.assertRaisesRegex(TSS2_Exception, "command code not supported"): self.ectx.ac_send(ESYS_TR.NONE, ESYS_TR.NONE, ESYS_TR.NONE, inData) @pytest.mark.skipif( not _lib_version_atleast("tss2-esapi", "4.0.0"), reason="Attached Components not supported prior to tss v4", ) def test_policy_ac_send_select(self): with self.assertRaisesRegex(TSS2_Exception, "command code not supported"): self.ectx.policy_ac_send_select( b"0123456789ABCDEF", b"0123456789ABCDEF", b"0123456789ABCDEF", TPMI_YES_NO.NO, ) def test_test_parms(self): parms = TPMT_PUBLIC_PARMS(type=TPM2_ALG.RSA) parms.parameters.rsaDetail.symmetric.algorithm = TPM2_ALG.NULL parms.parameters.rsaDetail.scheme.scheme = TPM2_ALG.NULL parms.parameters.rsaDetail.keyBits = 2048 parms.parameters.rsaDetail.exponent = 0 self.ectx.test_parms(parms) parms.parameters.rsaDetail.keyBits = 1234 with self.assertRaises(TSS2_Exception) as e: self.ectx.test_parms(parms) self.assertEqual(e.exception.error, TPM2_RC.VALUE) self.assertEqual(e.exception.parameter, 1) def test_read_clock(self): ctime = self.ectx.read_clock() self.assertGreater(ctime.time, 0) self.assertGreater(ctime.clockInfo.clock, 0) def test_clock_set(self): newtime = 0xFA1AFE1 self.ectx.clock_set(newtime) ntime = self.ectx.read_clock() self.assertGreaterEqual(ntime.clockInfo.clock, newtime) with self.assertRaises(TSS2_Exception) as e: self.ectx.clock_set(0) self.assertEqual(e.exception.error, TPM2_RC.VALUE) def test_clock_rate_adjust(self): self.ectx.clock_rate_adjust(TPM2_CLOCK.COARSE_SLOWER) def test_nv_undefine_space_special(self): # pre-generated TPM2_PolicyCommandCode(TPM2_CC_NV_UndefineSpaceSpecial) pol = b"\x1d-\xc4\x85\xe1w\xdd\xd0\xa4\n4I\x13\xce\xebB\x0c\xaa\t str: """Generate a random id which can be used e.g. for unique key names.""" return "".join(random.choices(string.digits, k=10)) def sha256(data: bytes) -> bytes: """Calculate the SHA256 digest of given data.""" digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(data) digest = digest.finalize() return digest # TODO unprovisioned tests @pytest.fixture(scope="class") def init_fapi_ecc(request, fapi_ecc): request.cls.fapi = fapi_ecc request.cls.profile_name = request.cls.fapi.config.profile_name yield request.cls.fapi @pytest.fixture(scope="class") def init_fapi_rsa(request, fapi_rsa): request.cls.fapi = fapi_rsa request.cls.profile_name = request.cls.fapi.config.profile_name yield request.cls.fapi class Common: @pytest.fixture def esys(self): with ESAPI(tcti=self.fapi.tcti) as esys: yield esys @pytest.fixture def cryptography_key(self): key = ec.generate_private_key(ec.SECP256R1(), backend=default_backend()) key_public_pem = ( key.public_key() .public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) .decode() ) return key, key_public_pem @pytest.fixture def sign_key(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, type_="sign, exportable") yield key_path self.fapi.delete(path=key_path) @pytest.fixture def decrypt_key(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, type_="decrypt") yield key_path self.fapi.delete(path=key_path) @pytest.fixture def seal(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" seal_data = random_uid().encode() self.fapi.create_seal(path=seal_path, data=seal_data) yield seal_path, seal_data self.fapi.delete(path=seal_path) @pytest.fixture def ext_key(self, cryptography_key): key, key_public_pem = cryptography_key key_path = f"/ext/key_{random_uid()}" self.fapi.import_object(path=key_path, import_data=key_public_pem) yield key_path, key self.fapi.delete(path=key_path) @pytest.fixture def nv_ordinary(self): nv_path = f"/nv/Owner/nv_{random_uid()}" # TODO Owner should be case insensitive (fix upstream)? self.fapi.create_nv(path=nv_path, size=10) yield nv_path self.fapi.delete(path=nv_path) @pytest.fixture def nv_increment(self): nv_path = f"/nv/Owner/nv_{random_uid()}" self.fapi.create_nv(path=nv_path, size=10, type_="counter") yield nv_path self.fapi.delete(path=nv_path) @pytest.fixture def nv_pcr(self): nv_path = f"/nv/Owner/nv_{random_uid()}" self.fapi.create_nv(path=nv_path, size=32, type_="pcr") yield nv_path self.fapi.delete(path=nv_path) @pytest.fixture def nv_bitfield(self): nv_path = f"/nv/Owner/nv_{random_uid()}" self.fapi.create_nv(path=nv_path, size=32, type_="bitfield") yield nv_path self.fapi.delete(path=nv_path) def test_provision_ok(self): provisioned = self.fapi.provision() assert provisioned is False def test_provision_fail(self): with pytest.raises(TSS2_Exception): self.fapi.provision(is_provisioned_ok=False) def test_get_random(self): random_bytes = self.fapi.get_random(42) assert type(random_bytes) == bytes assert len(random_bytes) == 42 def test_get_random_zero(self): random_bytes = self.fapi.get_random(0) assert type(random_bytes) == bytes assert len(random_bytes) == 0 def test_get_random_large(self): with pytest.raises(OverflowError): self.fapi.get_random(0xFFFFFFFFFFFFFFFF + 1) def test_get_random_negative(self): with pytest.raises(OverflowError): self.fapi.get_random(-1) def test_get_info(self): info = self.fapi.get_info() assert type(info) is str json.loads(info) assert "capabilities" in info def test_list(self): profile_name = self.fapi.config.profile_name path_list = self.fapi.list() assert type(path_list) is list assert len(path_list) > 0 assert type(path_list[0]) is str assert f"/{profile_name}/HS" in path_list def test_list_search_path(self): profile_name = self.fapi.config.profile_name search_path = f"/{profile_name}/HE" path_list = self.fapi.list(search_path) assert type(path_list) is list assert len(path_list) > 0 assert type(path_list[0]) is str assert all(path.startswith(search_path) for path in path_list) def test_list_bad_search_path(self): with pytest.raises(TSS2_Exception): self.fapi.list("/nonexistent") def test_create_key(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/key_{random_uid()}" created = self.fapi.create_key(path=key_path) assert created is True assert key_path in self.fapi.list() def test_create_key_double_ok(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/key_{random_uid()}" created = self.fapi.create_key(path=key_path) assert created is True assert key_path in self.fapi.list() created = self.fapi.create_key(path=key_path, exists_ok=True) assert created is False def test_create_key_double_fail(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/key_{random_uid()}" created = self.fapi.create_key(path=key_path) assert created is True assert key_path in self.fapi.list() with pytest.raises(TSS2_Exception): self.fapi.create_key(path=key_path) def test_get_esys_blob_contextload(self, esys, sign_key): blob_data, blob_type = self.fapi.get_esys_blob(path=sign_key) assert blob_type == FAPI_ESYSBLOB.CONTEXTLOAD esys_handle = esys.load_blob(blob_data, blob_type) esys.read_public(esys_handle) esys.flush_context(esys_handle) def test_get_esys_blob_bad(self, esys): with pytest.raises(ValueError) as e: esys.load_blob(None, 1234) assert ( str(e.value) == "Expected type_ to be FAPI_ESYSBLOB.CONTEXTLOAD or FAPI_ESYSBLOB.DESERIALIZE, got 1234" ) def test_get_esys_blob_deserialize(self, esys, nv_ordinary): blob_data, blob_type = self.fapi.get_esys_blob(path=nv_ordinary) assert blob_type == FAPI_ESYSBLOB.DESERIALIZE esys_handle = esys.load_blob(blob_data, blob_type) esys.nv_read_public(esys_handle) def test_verify(self, ext_key): # create signature externally key_path, key = ext_key message = b"Hello World" signature = key.sign(message, ec.ECDSA(hashes.SHA256())) # verify signature via fapi self.fapi.verify_signature(key_path, sha256(message), signature) def test_verify_fail(self, ext_key): key_path, key = ext_key with pytest.raises(TSS2_Exception): self.fapi.verify_signature( key_path, digest=b"A" * 32, signature=b"bad signature" ) # TODO test encrypt with RSA profile. Needs to be provisioned separately. @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2"), reason="tpm2-tss bug, see #2028" ) def test_import_key_double_ok(self, cryptography_key): key, key_public_pem = cryptography_key key_path = f"/ext/key_{random_uid()}" imported = self.fapi.import_object(path=key_path, import_data=key_public_pem) assert imported is True assert key_path in self.fapi.list() imported = self.fapi.import_object( path=key_path, import_data=key_public_pem, exists_ok=True ) assert imported is False @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2"), reason="tpm2-tss bug, see #2028" ) def test_import_key_double_fail(self, cryptography_key): key, key_public_pem = cryptography_key key_path = f"/ext/key_{random_uid()}" imported = self.fapi.import_object(path=key_path, import_data=key_public_pem) assert imported is True assert key_path in self.fapi.list() with pytest.raises(TSS2_Exception): self.fapi.import_object(path=key_path, import_data=key_public_pem) @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2"), reason="tpm2-tss bug, see #2028" ) def test_import_policy_double_ok(self): policy = """ { "description":"Description of this policy", "policy":[{"type": "POLICYAUTHVALUE"}] } """ policy_path = f"/policy/policy_{random_uid()}" imported = self.fapi.import_object(path=policy_path, import_data=policy) assert imported is True assert policy_path in self.fapi.list() imported = self.fapi.import_object( path=policy_path, import_data=policy, exists_ok=True ) assert imported is False @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2"), reason="tpm2-tss bug, see #2028" ) def test_import_policy_double_fail(self): policy = """ { "description":"Description of this policy", "policy":[{"type": "POLICYAUTHVALUE"}] } """ policy_path = f"/policy/policy_{random_uid()}" imported = self.fapi.import_object(path=policy_path, import_data=policy) assert imported is True assert policy_path in self.fapi.list() with pytest.raises(TSS2_Exception): self.fapi.import_object(path=policy_path, import_data=policy) def test_import_exported_key(self, sign_key): exported_data = self.fapi.export_key(path=sign_key) profile_name = self.fapi.config.profile_name new_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.import_object(path=new_path, import_data=exported_data) def test_export_imported_policy(self): policy = """ { "description":"Description of this policy", "policy":[{"type": "POLICYAUTHVALUE"}] } """ policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy) exported_policy = self.fapi.export_policy(path=policy_path) assert type(exported_policy) == str assert "Description of this policy" in exported_policy def test_create_seal(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" seal_data = "Hello World" created = self.fapi.create_seal(path=seal_path, data=seal_data) assert created is True assert seal_path in self.fapi.list() def test_create_seal_double_ok(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" seal_data = "Hello World" created = self.fapi.create_seal(path=seal_path, data=seal_data) assert created is True assert seal_path in self.fapi.list() created = self.fapi.create_seal(path=seal_path, data=seal_data, exists_ok=True) assert created is False def test_create_seal_double_fail(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" seal_data = "Hello World" created = self.fapi.create_seal(path=seal_path, data=seal_data) assert created is True assert seal_path in self.fapi.list() with pytest.raises(TSS2_Exception): self.fapi.create_seal(path=seal_path, data=seal_data) def test_create_seal_random(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" seal_len = 12 created = self.fapi.create_seal(path=seal_path, size=seal_len) assert created is True assert seal_path in self.fapi.list() unseal_data = self.fapi.unseal(path=seal_path) assert type(unseal_data) is bytes assert len(unseal_data) == seal_len def test_create_seal_both_data_and_size_fail(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" with pytest.raises(ValueError): self.fapi.create_seal(path=seal_path, data="Hello World", size=11) def test_create_seal_neither_data_nor_size_fail(self): profile_name = self.fapi.config.profile_name seal_path = f"/{profile_name}/HS/SRK/seal_{random_uid()}" with pytest.raises(ValueError): self.fapi.create_seal(path=seal_path) def test_unseal(self, seal): seal_path, seal_data = seal unseal_data = self.fapi.unseal(path=seal_path) assert type(unseal_data) is bytes assert seal_data == unseal_data def test_quote_verify(self, sign_key): info, signature, pcr_log, certificate = self.fapi.quote( path=sign_key, pcrs=[7, 9] ) info_json = json.loads(info) assert info_json["attest"]["type"] == "ATTEST_QUOTE" assert type(signature) is bytes pcr_log_json = json.loads(pcr_log) assert type(pcr_log_json) == list assert certificate == "" # TODO verify via openssl # exported_data = self.fapi.export_key(path=sign_key) # sign_key_public_pem = json.loads(exported_data)["pem_ext_public"].encode() # public_key = serialization.load_pem_public_key(sign_key_public_pem) # message = b"TODO" # public_key.verify(signature, message, ec.ECDSA(hashes.SHA256())) # signature via fapi self.fapi.verify_quote(path=sign_key, signature=signature, quote_info=info) def test_export_key(self, sign_key): exported_data = self.fapi.export_key(path=sign_key) assert type(exported_data) is str json.loads(exported_data) def test_delete_key(self): profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/key_{random_uid()}" self.fapi.create_key(path=key_path) assert key_path in self.fapi.list() self.fapi.delete(path=key_path) assert key_path not in self.fapi.list() def test_set_get_description(self, sign_key): description = "Nobody expects the Spanish Inquisition!" self.fapi.set_description(path=sign_key, description=description) returned_description = self.fapi.get_description(path=sign_key) assert description == returned_description def test_get_empty_description(self, sign_key): description = self.fapi.get_description(path=sign_key) assert description == "" def test_set_get_app_data(self, sign_key): app_data = b"\x00\xDE\xCA\xFB\xAD\x00" self.fapi.set_app_data(path=sign_key, app_data=app_data) returned_app_data = self.fapi.get_app_data(path=sign_key) assert app_data == returned_app_data def test_get_no_app_data(self, sign_key): app_data = self.fapi.get_app_data(path=sign_key) assert app_data is None def test_set_get_certificate(self, sign_key): certificate = "" self.fapi.set_certificate(path=sign_key, certificate=certificate) returned_certificate = self.fapi.get_certificate(path=sign_key) assert certificate == returned_certificate def test_get_empty_certificate(self, sign_key): certificate = self.fapi.get_certificate(path=sign_key) assert certificate == "" def test_get_empty_platform_certificates_ok(self): certificates = self.fapi.get_platform_certificates(no_cert_ok=True) assert certificates == b"" def test_get_empty_platform_certificates_fail(self): with pytest.raises(TSS2_Exception): self.fapi.get_platform_certificates() def test_pcr_read(self): value, log = self.fapi.pcr_read(7) log_json = json.loads(log) assert value == b"\0" * 32 assert type(log_json) == list def test_pcr_extend_read(self): index = 16 value_old, _ = self.fapi.pcr_read(index) data = b"\x11" * 100 log = '{"test":"myfile"}' self.fapi.pcr_extend(index, data, log) returned_value, returned_log = self.fapi.pcr_read(index) assert returned_value == sha256(value_old + sha256(data)) assert '"test":"myfile"' in returned_log def test_nv_write_read(self, nv_ordinary): data = b"ABCDEFGHIJ" # 10 bytes as defined in fixture self.fapi.nv_write(nv_ordinary, data) returned_data, log = self.fapi.nv_read(nv_ordinary) assert returned_data == data assert log == "" def test_nv_increment(self, nv_increment): # TODO initial increment should not be necessary, check in with upstream self.fapi.nv_increment(nv_increment) data_before, log = self.fapi.nv_read(nv_increment) assert len(data_before) == 8 assert log == "" self.fapi.nv_increment(nv_increment) data_after, log = self.fapi.nv_read(nv_increment) assert len(data_after) == 8 assert log == "" assert int.from_bytes(data_before, byteorder="big") + 1 == int.from_bytes( data_after, byteorder="big" ) def test_nv_pcr(self, nv_pcr): value_old = b"\x00" * 32 data = b"\x11" * 100 log = '{"test":"myfile"}' self.fapi.nv_extend(nv_pcr, data, log) returned_value, returned_log = self.fapi.nv_read(nv_pcr) assert returned_value == sha256(value_old + data) assert '"test":"myfile"' in returned_log def test_nv_set_bits(self, nv_bitfield): bitfield = 0x0000DECAFBAD0000 self.fapi.nv_set_bits(nv_bitfield, bitfield) returned_value, returned_log = self.fapi.nv_read(nv_bitfield) assert returned_value == bitfield.to_bytes(8, byteorder="big") assert returned_log == "" def test_set_auth_callback(self, sign_key): def callback(path, descr, user_data): print(f"Callback: path={path}, descr={descr}, user_data={user_data}") return user_data profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, auth_value=b"123456") self.fapi.set_auth_callback(callback, user_data=b"123456") self.fapi.sign(key_path, b"\x11" * 32) self.fapi.change_auth(path=key_path, auth_value=b"ABCDEF") self.fapi.set_auth_callback(callback, user_data=b"ABCDEF") self.fapi.sign(key_path, b"\x22" * 32) def test_unset_auth_callback(self, sign_key): def callback(path, descr, user_data): print(f"Callback: path={path}, descr={descr}, user_data={user_data}") return user_data profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, auth_value=b"123456") self.fapi.set_auth_callback(callback, user_data=b"123456") self.fapi.sign(key_path, b"\x11" * 32) self.fapi.change_auth(path=key_path, auth_value=None) self.fapi.set_auth_callback(callback=None) self.fapi.sign(key_path, b"\x22" * 32) @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"]), reason="tpm2-tss bug, see #2084", ) def test_write_authorize_nv(self, esys): # write CommandCode policy for sign key into nv index nv_path = f"/nv/Owner/nv_policy_{random_uid()}" policy = """ { "description": "", "policy": [ { "type": "CommandCode", "code": "sign" } ] }""" policy_auth_nv_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_auth_nv_path, import_data=policy) self.fapi.create_nv(path=nv_path, size=34) self.fapi.write_authorize_nv(nv_path, policy_auth_nv_path) # create key with AuthorizeNV policy (which ties the above policy, stored in the nv index, to the key) policy_auth_nv = f""" {{ "description":"Description pol_authorize_nv", "policy":[ {{ "type": "AuthorizeNV", "nvPath": "{nv_path}", }} ] }} """ policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy_auth_nv) profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, type_="sign", policy_path=policy_path) # use key for signing: success self.fapi.sign(path=key_path, digest=b"\x11" * 32) # use key for quoting: fail with pytest.raises(TSS2_Exception): self.fapi.quote(path=key_path, pcrs=[7, 9]) @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"]), reason="tpm2-tss bug, see #2084", ) def test_authorize_policy(self, sign_key): # create policy Authorize, which is satisfied via a signature by sign_key policy_authorize_path = f"/policy/policy_{random_uid()}" policy_authorize = f""" {{ "description": "Description pol_authorize", "policy": [ {{ "type": "Authorize", "policyRef": [1, 2, 3, 4, 5], "keyPath": "{sign_key}", }} ] }} """ self.fapi.import_object( path=policy_authorize_path, import_data=policy_authorize ) # create policy CommandCode policy = """ { "description": "", "policy": [ { "type": "CommandCode", "code": "sign" } ] }""" policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy) # create key which can only be used if policy Authorize is satisfied profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key( path=key_path, type_="sign", policy_path=policy_authorize_path ) # try to use key without satisfying policy Authorize: fail with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) # specify underlying policy CommandCode and use key: success self.fapi.authorize_policy( policy_path=policy_path, key_path=sign_key, policy_ref=b"\x01\x02\x03\x04\x05", ) self.fapi.sign(path=key_path, digest=b"\x11" * 32) # specify underlying policy CommandCode and use key: fail because policy CommandCode is not satisfied self.fapi.authorize_policy( policy_path=policy_path, key_path=sign_key, policy_ref=b"\x01\x02\x03\x04\x05", ) with pytest.raises(TSS2_Exception): self.fapi.quote(path=key_path, pcrs=[7, 9]) @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2"), reason="tpm2-tss bug, see #2080" ) def test_policy_signed(self, cryptography_key): # create external signing key used by the signing authority external to the TPM sign_key, sign_key_public_pem = cryptography_key # create policy Signed, which is satisfied via a signature by sign_key policy = f""" {{ "description": "Description pol_signed", "policy": [ {{ "type": "PolicySigned", "publicKeyHint": "Test key hint", "keyPEM": "{sign_key_public_pem}", }} ] }} """ policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy) # create key which can only be used if policy Signed is satisfied profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, type_="sign", policy_path=policy_path) # try to use key without satisfying policy Signed: fail with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) def sign_callback( path, description, public_key, public_key_hint, hash_alg, data_to_sign, user_data, ): assert key_path.endswith(path) assert description == "PolicySigned" assert public_key == sign_key_public_pem assert public_key_hint == "Test key hint" assert hash_alg == lib.TPM2_ALG_SHA256 assert user_data == b"123456" # signing authority signs external to TPM (via openssl) to authorize usage of key (policy Signed) return sign_key.sign(data_to_sign, ec.ECDSA(hashes.SHA256())) # set signing callback, will be called if policy Signed is to be satisfied self.fapi.set_sign_callback(callback=sign_callback, user_data=b"123456") # use key for signing: success self.fapi.sign(path=key_path, digest=b"\x11" * 32) # unset signing callback, should fail self.fapi.set_sign_callback(callback=None) with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) def test_policy_branched(self): pcr_index = 15 pcr_data = b"ABCDEF" pcr_digest, _ = self.fapi.pcr_read(index=pcr_index) pcr_digest = sha256(pcr_digest + sha256(pcr_data)) # create policy Signed, which is satisfied via a signature by sign_key policy = f""" {{ "description": "Read, Password for write", "policy": [ {{ "type": "PolicyOR", "branches": [ {{ "name": "Read", "description": "des", "policy": [ {{ "type": "CommandCode", "code": "NV_READ" }} ] }}, {{ "name": "Write", "description": "dgf", "policy": [ {{ "type": "CommandCode", "code": "NV_WRITE" }}, {{ "type": "PolicyPCR", "pcrs":[ {{ "pcr": {pcr_index}, "hashAlg": "TPM2_ALG_SHA256", "digest": "{binascii.hexlify(pcr_digest).decode()}" }} ] }} ] }} ] }} ] }} """ policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy) # create key which can only be used if policy Signed is satisfied nv_path = f"/nv/Owner/nv_{random_uid()}" self.fapi.create_nv(path=nv_path, size=11, policy_path=policy_path) def branch_callback(path, description, branch_names, user_data): assert path == nv_path assert description == "PolicyOR" assert branch_names == ["Read", "Write"] assert user_data == b"123456" return policy_coice(branch_names) # set branch callback, will be called if the nv index is accessed self.fapi.set_branch_callback(callback=branch_callback, user_data=b"123456") # at first, we will choose the 'Write' branch policy_coice = lambda options: options.index("Write") # write to nv index: fail with pytest.raises(TSS2_Exception): self.fapi.nv_write(path=nv_path, data="Hello World") # satisfy policy PCR (and thus policy OR) self.fapi.pcr_extend(index=pcr_index, data=pcr_data) # write to nv index: success self.fapi.nv_write(path=nv_path, data="Hello World") # extend PCR so policy PCR cannot be satisfied anymore self.fapi.pcr_extend( index=pcr_index, data="nobody expects the spanish inquisition!" ) # secondly, we will choose the 'Read' branch policy_coice = lambda options: options.index("Read") # use the 'Read' branch (satisfied via policy CommandCode) nv_data, _ = self.fapi.nv_read(nv_path) assert nv_data == b"Hello World" policy_coice = None # thirdly, we set different branch callback function (here lambda) and read again self.fapi.set_branch_callback( callback=lambda _path, _description, branch_names, _user_data: branch_names.index( "Read" ) ) nv_data, _ = self.fapi.nv_read(nv_path) assert nv_data == b"Hello World" # test without a callback set if not is_bug_fixed(fixed_in="3.1", backports=["2.4.3", "3.0.1", "3.1.0"]): # skip tests as theirs a bug return self.fapi.set_branch_callback(callback=None) with pytest.raises(TSS2_Exception): self.fapi.nv_read(nv_path) # clean up self.fapi.delete(path=nv_path) @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"]), reason="tpm2-tss bug, see #2089", ) def test_policy_action(self): # create policy Action, which is satisfied via the callback policy = f""" {{ "description":"The description", "policy":[ {{ "type": "POLICYACTION", "action": "myaction" }} ] }} """ # noqa: F541 ruff is wrong here policy_path = f"/policy/policy_{random_uid()}" self.fapi.import_object(path=policy_path, import_data=policy) # create key which can only be used if policy Action is satisfied profile_name = self.fapi.config.profile_name key_path = f"/{profile_name}/HS/SRK/key_{random_uid()}" self.fapi.create_key(path=key_path, type_="sign", policy_path=policy_path) # try to use key without satisfying policy Action: fail with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) def policy_action_callback_error(path, action, user_data) -> None: assert f"/{path}" == key_path assert action == "myaction" assert user_data == b"123456" raise ValueError("Policy Action: Invalid action.") # set policy Action callback, will be called if policy Action is to be satisfied self.fapi.set_policy_action_callback( callback=policy_action_callback_error, user_data=b"123456" ) # try to use key with policy Action that raises an exception: fail with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) # set policy Action callback to lambda, returning success self.fapi.set_policy_action_callback(callback=lambda *_: None) # use key for signing: success self.fapi.sign(path=key_path, digest=b"\x11" * 32) # set policy Action callback to NULL self.fapi.set_policy_action_callback(callback=None) with pytest.raises(TSS2_Exception): self.fapi.sign(path=key_path, digest=b"\x11" * 32) def test_nv_create_double_ok(self): nv_path = f"/nv/Owner/nv_{random_uid()}" created = self.fapi.create_nv(path=nv_path, size=10) assert created == True created = self.fapi.create_nv(path=nv_path, size=10, exists_ok=True) assert created == False def test_nv_create_double_fail(self): nv_path = f"/nv/Owner/nv_{random_uid()}" created = self.fapi.create_nv(path=nv_path, size=10) assert created == True with pytest.raises(TSS2_Exception): self.fapi.create_nv(path=nv_path, size=10) @pytest.mark.usefixtures("init_fapi_ecc") class TestFapiECC(Common): def test_sign(self, sign_key): # create signature message = b"Hello World" digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(message) digest = digest.finalize() signature, key_public_pem, cert_pem = self.fapi.sign( path=sign_key, digest=digest ) assert type(signature) == bytes assert type(key_public_pem) == bytes assert type(cert_pem) == bytes # verify via fapi self.fapi.verify_signature(sign_key, digest, signature) # verify via openssl public_key = serialization.load_pem_public_key( key_public_pem, backend=default_backend() ) public_key.verify(signature, message, ec.ECDSA(hashes.SHA256())) def test_get_tpm_blobs(self, sign_key): tpm_2b_public, tpm_2b_private, policy = self.fapi.get_tpm_blobs(path=sign_key) assert tpm_2b_public.size == 0x56 assert tpm_2b_public.publicArea.type == lib.TPM2_ALG_ECC assert tpm_2b_public.publicArea.nameAlg == lib.TPM2_ALG_SHA256 assert ( tpm_2b_public.publicArea.objectAttributes == lib.TPMA_OBJECT_SIGN_ENCRYPT | lib.TPMA_OBJECT_USERWITHAUTH | lib.TPMA_OBJECT_SENSITIVEDATAORIGIN ) assert tpm_2b_public.publicArea.authPolicy.size == 0 assert ( tpm_2b_public.publicArea.parameters.eccDetail.symmetric.algorithm == lib.TPM2_ALG_NULL ) assert ( tpm_2b_public.publicArea.parameters.eccDetail.scheme.scheme == lib.TPM2_ALG_NULL ) assert ( tpm_2b_public.publicArea.parameters.eccDetail.curveID == lib.TPM2_ECC_NIST_P256 ) assert ( tpm_2b_public.publicArea.parameters.eccDetail.kdf.scheme == lib.TPM2_ALG_NULL ) assert tpm_2b_private.size == 0x7E assert policy == "" @pytest.mark.usefixtures("init_fapi_rsa") class TestFapiRSA(Common): def test_sign(self, sign_key): # create signature message = b"Hello World" digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(message) digest = digest.finalize() signature, key_public_pem, cert_pem = self.fapi.sign( path=sign_key, digest=digest ) assert type(signature) == bytes assert type(key_public_pem) == bytes assert type(cert_pem) == bytes # verify via fapi self.fapi.verify_signature(sign_key, digest, signature) # verify via openssl public_key = serialization.load_pem_public_key( key_public_pem, backend=default_backend() ) public_key.verify( signature, message, PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=32), hashes.SHA256(), ) def test_get_tpm_blobs(self, sign_key): tpm_2b_public, tpm_2b_private, policy = self.fapi.get_tpm_blobs(path=sign_key) assert tpm_2b_public.size == 0x116 assert tpm_2b_public.publicArea.type == lib.TPM2_ALG_RSA assert tpm_2b_public.publicArea.nameAlg == lib.TPM2_ALG_SHA256 assert ( tpm_2b_public.publicArea.objectAttributes == lib.TPMA_OBJECT_SIGN_ENCRYPT | lib.TPMA_OBJECT_USERWITHAUTH | lib.TPMA_OBJECT_SENSITIVEDATAORIGIN ) assert tpm_2b_public.publicArea.authPolicy.size == 0 assert ( tpm_2b_public.publicArea.parameters.rsaDetail.symmetric.algorithm == lib.TPM2_ALG_NULL ) assert ( tpm_2b_public.publicArea.parameters.rsaDetail.scheme.scheme == lib.TPM2_ALG_NULL ) assert tpm_2b_public.publicArea.parameters.rsaDetail.keyBits == 2048 assert tpm_2b_public.publicArea.parameters.rsaDetail.exponent == 0 assert tpm_2b_private.size == 0xDE assert policy == "" @pytest.mark.skipif( not is_bug_fixed(fixed_in="3.2", backports=["2.4.7", "3.0.5", "3.1.1"]), reason="tpm2-tss bug, see #2092", ) def test_encrypt_decrypt(self, decrypt_key): plaintext = b"Hello World!" ciphertext = self.fapi.encrypt(decrypt_key, plaintext) assert isinstance(ciphertext, bytes) decrypted = self.fapi.decrypt(decrypt_key, ciphertext) assert decrypted == plaintext if __name__ == "__main__": sys.exit(pytest.main(sys.argv)) tpm2-pytss-3.0.0-rc0/test/test_import.py000066400000000000000000000031561506405471500201540ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import sys import unittest class mocklib: def __init__(self, msg): self.msg = msg @property def lib(self): raise ImportError(self.msg) class ImportTest(unittest.TestCase): def test_missing_symbol(self): if "tpm2_pytss" in sys.modules: del sys.modules["tpm2_pytss"] sys.modules["tpm2_pytss._libtpm2_pytss"] = mocklib( "/tmp/tpm2_pytss/_libtpm2_pytss.abi3.so: undefined symbol: test_symbol" ) with self.assertRaises(ImportError) as e: import tpm2_pytss # noqa: F401 self.assertEqual( e.exception.msg, "failed to load tpm2-tss bindigs in /tmp/tpm2_pytss/_libtpm2_pytss.abi3.so" + " due to missing symbol test_symbol, ensure that you are using the same" + " libraries the python module was built against.", ) def test_other_message(self): if "tpm2_pytss" in sys.modules: del sys.modules["tpm2_pytss"] sys.modules["tpm2_pytss._libtpm2_pytss"] = mocklib("I am a teapot") with self.assertRaises(ImportError) as e: import tpm2_pytss # noqa: F401 self.assertEqual(e.exception.msg, "I am a teapot") def test_not_missing_symbol(self): if "tpm2_pytss" in sys.modules: del sys.modules["tpm2_pytss"] sys.modules["tpm2_pytss._libtpm2_pytss"] = mocklib("/bin/ls: not a: teapot") with self.assertRaises(ImportError) as e: import tpm2_pytss # noqa: F401 self.assertEqual(e.exception.msg, "/bin/ls: not a: teapot") tpm2-pytss-3.0.0-rc0/test/test_internal.py000066400000000000000000000117521506405471500204570ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest from tpm2_pytss.internal.utils import TSS2Version class InternalTest(unittest.TestCase): def test_lib_version_strings(self): versions = [] # try the variants with a single major number versions.append(TSS2Version("1-rc0")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_00000000_00000000_00 ) versions.append(TSS2Version("1-rc0-dirty")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_00000000_00000000_01 ) versions.append(TSS2Version("1-rc0-2-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_00000000_00000002_00 ) versions.append(TSS2Version("1-rc0-2-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_00000000_00000002_01 ) versions.append(TSS2Version("1")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_FFFFFFFF_00000000_00 ) versions.append(TSS2Version("1-5-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_FFFFFFFF_00000005_00 ) versions.append(TSS2Version("1-5-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000001_00000000_00000000_FFFFFFFF_00000005_01 ) # try major minor variants versions.append(TSS2Version("2.0-rc0")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_00000000_00000000_00 ) versions.append(TSS2Version("2.0-rc0-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_00000000_00000000_01 ) versions.append(TSS2Version("2.0-rc0-2-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_00000000_00000002_00 ) versions.append(TSS2Version("2.0-rc0-2-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_00000000_00000002_01 ) versions.append(TSS2Version("2.0")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_FFFFFFFF_00000000_00 ) versions.append(TSS2Version("2.0-5-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_FFFFFFFF_00000005_00 ) versions.append(TSS2Version("2.0-5-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000000_FFFFFFFF_00000005_01 ) # try major minor patch variants versions.append(TSS2Version("2.0.1-rc0")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_00000000_00000000_00 ) versions.append(TSS2Version("2.0.1-rc0-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_00000000_00000000_01 ) versions.append(TSS2Version("2.0.1-rc0-2-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_00000000_00000002_00 ) versions.append(TSS2Version("2.0.1-rc0-2-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_00000000_00000002_01 ) versions.append(TSS2Version("2.0.1")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_FFFFFFFF_00000000_00 ) versions.append(TSS2Version("2.0.1-5-g0fd1c5fbbaf2")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_FFFFFFFF_00000005_00 ) versions.append(TSS2Version("2.0.1-5-g0fd1c5fbbaf2-dirty")) self.assertEqual( versions[-1], 0x00000002_00000000_00000001_FFFFFFFF_00000005_01 ) # We carefully built this list in sorted order so everything should be ascending # in value or precedence related to index. It value at index 5 is greater than # the value at index 2 v0 = versions[0] for v1 in versions[1:]: self.assertTrue(v0 < v1, f"{str(v0)} not less than {str(v1)}") v0 = v1 with self.assertRaises(ValueError, msg='Invalid version string, got: "1.N.0"'): TSS2Version("1.N.0") with self.assertRaises(ValueError, msg='Invalid version string, got: "N.1.0"'): TSS2Version("N.1.0") with self.assertRaises(ValueError, msg='Invalid version string, got: "3.1.N"'): TSS2Version("3.1.N") with self.assertRaises( ValueError, msg='Invalid version string, got: "3.1.0-N-g0fd1c5fbbaf2-dirty"' ): TSS2Version("3.1.0-N-g0fd1c5fbbaf2-dirty") with self.assertRaises( ValueError, msg='Invalid version string, got: "3.1.0-126-g0fd1c5fbbaf2-bad"' ): TSS2Version("3.1.0-126-g0fd1c5fbbaf2-bad") if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_policy.py000066400000000000000000000747251506405471500201530ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest import textwrap import json from tpm2_pytss import * from tpm2_pytss.internal.utils import _lib_version_atleast from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature from .TSS2_BaseTest import TSS2_EsapiTest if not _lib_version_atleast("tss2-policy", "4.0.0"): raise unittest.SkipTest("tss2-policy not installed or version is less then 4.0.0") def lowercase_dict(src): if not isinstance(src, dict): return src dest = dict() for k, v in src.items(): if isinstance(v, str): lv = v.lower() dest[k] = lv elif isinstance(v, dict): dest[k] = lowercase_dict(v) elif isinstance(v, list): l = list() for e in v: if isinstance(e, str): le = e.lower() elif isinstance(e, dict): le = lowercase_dict(e) else: le = e l.append(le) dest[k] = l else: dest[k] = v return dest class TestPolicy(TSS2_EsapiTest): def setUp(self): super().setUp() self._has_secp192r1 = True try: ec.generate_private_key(ec.SECP192R1()) except Exception: self._has_secp192r1 = False def test_password_policy(self): pol = { "description": "this is a policy", "policy": [{"type": "POLICYPASSWORD"}], } calcpol = { "description": "this is a policy", "policyDigests": [ { "digest": "af6038c78c5c962d37127e319124e3a8dc582e9b", "hashAlg": "SHA1", } ], "policy": [ { "type": "POLICYPASSWORD", "policyDigests": [ { "digest": "af6038c78c5c962d37127e319124e3a8dc582e9b", "hashAlg": "SHA1", } ], } ], } polstr = json.dumps(pol).encode() with policy(polstr, TPM2_ALG.SHA1) as p: desc = p.description polp = p.policy halg = p.hash_alg p.calculate() dig = p.get_calculated_digest() cjb = p.get_calculated_json() self.assertEqual(desc, b"this is a policy") self.assertEqual(polp, polstr) self.assertEqual(halg, TPM2_ALG.SHA1) self.assertEqual( dig.buffer, b"\xaf`8\xc7\x8c\\\x96-7\x12~1\x91$\xe3\xa8\xdcX.\x9b" ) cj = json.loads(cjb) self.assertEqual(lowercase_dict(cj), lowercase_dict(calcpol)) def test_password_policy_execute(self): pol = { "description": "this is a policy", "policy": [{"type": "POLICYPASSWORD"}], } polstr = json.dumps(pol).encode() session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA1, ) with policy(polstr, TPM2_ALG.SHA1) as p: p.execute(self.ectx, session) dig2b = self.ectx.policy_get_digest(session) self.assertEqual( dig2b.buffer, b"\xaf`8\xc7\x8c\\\x96-7\x12~1\x91$\xe3\xa8\xdcX.\x9b" ) def test_callbacks(self): pol = { "description": "this is a policy", "policy": [{"type": "POLICYPASSWORD"}], } polstr = json.dumps(pol) def test(): pass p = policy(polstr, TPM2_ALG.SHA256) p.set_callback(policy_cb_types.CALC_PCR, test) cb = p._get_callback(policy_cb_types.CALC_PCR) self.assertEqual(cb, test) p.set_callback(policy_cb_types.CALC_PCR, None) cb = p._get_callback(policy_cb_types.CALC_PCR) self.assertEqual(cb, None) with self.assertRaises(ValueError) as e: p.set_callback(1234, test) self.assertEqual(str(e.exception), "unsupported callback type 1234") def test_calc_pcr_callback(self): pol = { "description": "this is a pcr policy", "policy": [{"type": "pcr", "currentPCRs": [0, 8]}], } calc_pol = { "description": "this is a pcr policy", "policyDigests": [ { "hashAlg": "SHA256", "digest": "e5a442791c55f8c4a3e391385e170a24c75add21bc2c140fc4f4a2628810f13f", } ], "policy": [ { "type": "POLICYPCR", "policyDigests": [ { "hashAlg": "SHA256", "digest": "e5a442791c55f8c4a3e391385e170a24c75add21bc2c140fc4f4a2628810f13f", } ], "pcrs": [ {"pcr": 0, "hashAlg": "SHA256", "digest": "00" * 32}, {"pcr": 8, "hashAlg": "SHA256", "digest": "08" * 32}, ], } ], } polstr = json.dumps(pol).encode() cb_called = False cb_selection = TSS2_POLICY_PCR_SELECTION() def pcr_cb(selection): nonlocal cb_called nonlocal cb_selection cb_called = True cb_selection = selection sel = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA256, sizeofSelect=selection.selections.pcr_select.sizeofSelect, pcrSelect=selection.selections.pcr_select.pcrSelect, ) out_sel = TPML_PCR_SELECTION((sel,)) digests = list() selb = bytes(sel.pcrSelect[0 : sel.sizeofSelect]) seli = int.from_bytes(reversed(selb), "big") for i in range(0, sel.sizeofSelect * 8): if (1 << i) & seli: dig = TPM2B_DIGEST(bytes([i]) * 32) digests.append(dig) out_dig = TPML_DIGEST(digests) return (out_sel, out_dig) with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PCR, pcr_cb) p.calculate() cjb = p.get_calculated_json() cj = json.loads(cjb) self.assertTrue(cb_called) self.assertIsInstance(cb_selection, TSS2_POLICY_PCR_SELECTION) self.assertEqual(cb_selection.type, TSS2_POLICY_PCR_SELECTOR.PCR_SELECT) self.assertEqual(cb_selection.selections.pcr_select.sizeofSelect, 3) self.assertEqual( bytes(cb_selection.selections.pcr_select.pcrSelect), b"\x01\x01\x00\x00" ) self.assertEqual(lowercase_dict(cj), lowercase_dict(calc_pol)) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PCR, bad_cb) p.calculate() self.assertEqual(str(e.exception), "callback exception") def test_calc_name_callback(self): pol = { "description": "this is a name policy", "policy": [{"type": "namehash", "namePaths": ["path1", "path2", "path3"]}], } calc_pol = { "description": "this is a name policy", "policyDigests": [ { "hashAlg": "SHA256", "digest": "7334f60c505d0007343c33e697cadce69ca56cebe7870ad68c65534b1eee5fa6", } ], "policy": [ { "type": "POLICYNAMEHASH", "policyDigests": [ { "hashAlg": "SHA256", "digest": "7334f60c505d0007343c33e697cadce69ca56cebe7870ad68c65534b1eee5fa6", } ], "nameHash": "15c6f51a0c7d0b68942d62b4eaf59b3240e819a566361b0b052f46e4422051d8", } ], } polstr = json.dumps(pol).encode() cb_called = 0 cb_names = list() def name_cb(name): nonlocal cb_called nonlocal cb_names cb_called += 1 cb_names.append(name) return TPM2B_NAME(b"\x00\x0b" + bytes([cb_called]) * 32) with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NAME, name_cb) p.calculate() cjb = p.get_calculated_json() cj = json.loads(cjb) self.assertEqual(cb_called, 3) self.assertEqual(cb_names, [b"path1", b"path2", b"path3"]) self.assertEqual(lowercase_dict(cj), lowercase_dict(calc_pol)) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NAME, bad_cb) p.calculate() self.assertEqual(str(e.exception), "callback exception") def test_calc_public_callback(self): pol = { "description": "this is a public policy", "policy": [{"type": "duplicationselect", "newParentPath": "parent_path"}], } calc_pol = { "description": "this is a public policy", "policyDigests": [ { "hashAlg": "SHA256", "digest": "fd6ba57a0029f93e76628ecffe78911df5c93cc24e5d53e06472e0c3dd116e76", } ], "policy": [ { "type": "POLICYDUPLICATIONSELECT", "policyDigests": [ { "hashAlg": "SHA256", "digest": "fd6ba57a0029f93e76628ecffe78911df5c93cc24e5d53e06472e0c3dd116e76", } ], "objectName": "", "newParentName": "000b6e59ef657bca3b9624088244e6f67ab28d7843a8f53df58e37c67b0df7152f44", "includeObject": "NO", }, ], } polstr = json.dumps(pol).encode() cb_path = None def public_cb(path): nonlocal cb_path cb_path = path return TPMT_PUBLIC.parse("rsa2048") with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PUBLIC, public_cb) p.calculate() cjb = p.get_calculated_json() cj = json.loads(cjb) self.assertEqual(cb_path, b"parent_path") self.assertEqual(lowercase_dict(cj), lowercase_dict(calc_pol)) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PUBLIC, bad_cb) p.calculate() self.assertEqual(str(e.exception), "callback exception") def test_calc_nvpublic_callback(self): pol = { "description": "this is a nvpublic policy", "policy": [{"type": "authorizenv", "nvPath": "nv_path"}], } calc_pol = { "description": "this is a nvpublic policy", "policyDigests": [ { "hashAlg": "SHA256", "digest": "31e4f72a6ca046ca0dc4a8765b400ac01fe76502b9b820e7927a50b253624494", } ], "policy": [ { "type": "POLICYAUTHORIZENV", "policyDigests": [ { "hashAlg": "SHA256", "digest": "31e4f72a6ca046ca0dc4a8765b400ac01fe76502b9b820e7927a50b253624494", } ], "nvPublic": { "nvIndex": 0x1000000, "nameAlg": "SHA256", "attributes": { "PPWRITE": 0, "OWNERWRITE": 0, "AUTHWRITE": 0, "POLICYWRITE": 0, "POLICY_DELETE": 0, "WRITELOCKED": 0, "WRITEALL": 0, "WRITEDEFINE": 0, "WRITE_STCLEAR": 0, "GLOBALLOCK": 0, "PPREAD": 0, "OWNERREAD": 0, "AUTHREAD": 0, "POLICYREAD": 0, "NO_DA": 0, "ORDERLY": 0, "CLEAR_STCLEAR": 0, "READLOCKED": 0, "WRITTEN": 1, "PLATFORMCREATE": 0, "READ_STCLEAR": 0, "TPM2_NT": "ORDINARY", }, "authPolicy": "", "dataSize": 0, }, }, ], } polstr = json.dumps(pol).encode() cb_nvpath = None cb_nvindex = None def nvpublic_cb(path, index): nonlocal cb_nvpath, cb_nvindex cb_nvpath = path cb_nvindex = index nvp = TPMS_NV_PUBLIC(nvIndex=0x1000000, nameAlg=TPM2_ALG.SHA256) return nvp with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NVPUBLIC, nvpublic_cb) p.calculate() cjb = p.get_calculated_json() cj = json.loads(cjb) self.assertEqual(cb_nvpath, b"nv_path") self.assertEqual(cb_nvindex, 0) self.assertIsInstance(cb_nvindex, TPM2_HANDLE) self.assertEqual(lowercase_dict(cj), lowercase_dict(calc_pol)) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NVPUBLIC, bad_cb) p.calculate() self.assertEqual(str(e.exception), "callback exception") def test_exec_auth_callback(self): pol = { "description": "this is an auth policy", "policy": [{"type": "nv", "nvIndex": "0x1000000", "operandB": "00"}], } polstr = json.dumps(pol).encode() nvp = TPMS_NV_PUBLIC( nvIndex=0x1000000, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=1, ) nvh = self.ectx.nv_define_space(None, TPM2B_NV_PUBLIC(nvp)) self.ectx.nv_write(nvh, b"\x00") session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA1, ) def nvpublic_cb(path, index): nonlocal nvp if index == 0x1000000: return nvp return None cb_name = TPM2B_NAME() def auth_cb(name): nonlocal cb_name nonlocal nvh cb_name = name return (nvh, nvh, ESYS_TR.PASSWORD) with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NVPUBLIC, nvpublic_cb) p.set_callback(policy_cb_types.EXEC_AUTH, auth_cb) p.execute(self.ectx, session) dig2b = self.ectx.policy_get_digest(session) self.assertEqual( cb_name, b"\x00\x0b\x11\xf2\x07J\x1e\xcde\xf8T\x1cU\x15T\x80\xbb<\xdb\x83\xbf\x10\xffy\x8b\x9bB\\n\xa8E\xbe\xeaP", ) self.assertEqual( dig2b, b"Ad\x9eq\xa0!\xc0\xef\xe8v\x053\x97x\xbd;\xfa\x9c\x14|" ) def bad_cb(name): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_NVPUBLIC, nvpublic_cb) p.set_callback(policy_cb_types.EXEC_AUTH, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_polsel_callback(self): pol = { "description": "this is a polsel policy", "policy": [ { "type": "or", "branches": [ { "name": "branch1", "description": "branch1 description", "policy": [{"type": "password"}], }, { "name": "branch2", "description": "branch2 description", "policy": [{"type": "locality", "locality": ["zero"]}], }, ], }, ], } polstr = json.dumps(pol).encode() session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) cb_auth_object = "" cb_branches = None def polsel_cb(auth_object, branches): nonlocal cb_auth_object nonlocal cb_branches cb_auth_object = auth_object cb_branches = branches return len(branches) - 1 with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLSEL, polsel_cb) p.execute(self.ectx, session) dig2b = self.ectx.policy_get_digest(session) self.assertEqual(cb_auth_object, None) self.assertEqual(cb_branches, [b"branch1", b"branch2"]) self.assertEqual( dig2b, b"8\x17\xfa\x84\x98\xf9\xf6\xa0s\xaa\xc5\x91r\x0b\xc4\xea\xdf3\xd6\xdb#\xd5\n\x05\x12\xd7\x8a\x84\xb5\xa3\xb2\xa1", ) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLSEL, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_sign_callback(self): if not self._has_secp192r1: self.skipTest("cryptography doesn't have secp192r1") private_key = textwrap.dedent( """ -----BEGIN PRIVATE KEY----- MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBgBJYQqvoPfXctJixFL lAzRLQaAFBHOoQyhNAMyAATAjqP6LEx2q1p5aUSAfSwIpr0NijnvyLfWtluYrqCJ sI7HNirP/FKiz8pIY3FAD18= -----END PRIVATE KEY----- """ ).encode("ascii") public_key = textwrap.dedent( """ -----BEGIN PUBLIC KEY----- MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEwI6j+ixMdqtaeWlEgH0sCKa9DYo5 78i31rZbmK6gibCOxzYqz/xSos/KSGNxQA9f -----END PUBLIC KEY----- """ ).encode("ascii") pol = { "description": "this is a sign policy", "policy": [ { "type": "signed", "publicKeyHint": "test key", "keyPEM": public_key.decode(), }, ], } polstr = json.dumps(pol).encode() session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) pkey = load_pem_private_key(private_key, password=None) cb_pem = None cb_key_hint = None cb_hash_alg = None cb_buf = None def sign_cb(pem, key_hint, hash_alg, buf): nonlocal pkey, cb_pem, cb_key_hint, cb_hash_alg, cb_buf cb_pem = pem cb_key_hint = key_hint cb_hash_alg = hash_alg cb_buf = buf sig = pkey.sign(buf, ec.ECDSA(hashes.SHA256())) return sig with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_SIGN, sign_cb) p.execute(self.ectx, session) dig2b = self.ectx.policy_get_digest(session) self.assertEqual(cb_pem, public_key.lstrip(b"\n")) self.assertEqual(cb_key_hint, b"test key") self.assertEqual(cb_hash_alg, TPM2_ALG.SHA256) self.assertEqual( dig2b, b"\xc6L!\x81v\x893\xee\x14)^eYi/\xa3\x88\xa6}\xbf\xf1\x86\x99\x90\x9e\x10fg99\xecL", ) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_SIGN, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_polauth_callback(self): if not self._has_secp192r1: self.skipTest("cryptography doesn't have secp192r1") private_key = textwrap.dedent( """ -----BEGIN PRIVATE KEY----- MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBgBJYQqvoPfXctJixFL lAzRLQaAFBHOoQyhNAMyAATAjqP6LEx2q1p5aUSAfSwIpr0NijnvyLfWtluYrqCJ sI7HNirP/FKiz8pIY3FAD18= -----END PRIVATE KEY----- """ ).encode("ascii") public_key = textwrap.dedent( """ -----BEGIN PUBLIC KEY----- MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEwI6j+ixMdqtaeWlEgH0sCKa9DYo5 78i31rZbmK6gibCOxzYqz/xSos/KSGNxQA9f -----END PUBLIC KEY----- """ ).encode("ascii") pol = { "description": "this is a polauth policy", "policy": [ { "type": "authorize", "keyPEM": public_key.decode(), "approvedPolicy": "01" * 32, "policyRef": "02" * 32, }, ], } polstr = json.dumps(pol).encode() session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.TRIAL, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) pkey = load_pem_private_key(private_key, password=None) cb_hash_alg = None cb_digest = None cb_policyref = None def polauth_cb(key_public, hash_alg, digest, policy_ref): nonlocal pkey, cb_hash_alg, cb_digest, cb_policyref cb_hash_alg = hash_alg cb_digest = digest cb_policyref = policy_ref buf = bytes(digest) + bytes(policy_ref) sig = pkey.sign(buf, ec.ECDSA(hashes.SHA256())) r, s = decode_dss_signature(sig) rlen = int(r.bit_length() / 8) + (r.bit_length() % 8 > 0) slen = int(s.bit_length() / 8) + (s.bit_length() % 8 > 0) rb = r.to_bytes(rlen, "big") sb = s.to_bytes(slen, "big") tpm_sig = TPMT_SIGNATURE( sigAlg=TPM2_ALG.ECDSA, signature=TPMU_SIGNATURE( ecdsa=TPMS_SIGNATURE_ECC( hash=TPM2_ALG.SHA256, signatureR=rb, signatureS=sb ) ), ) return tpm_sig with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLAUTH, polauth_cb) p.execute(self.ectx, session) self.assertEqual(cb_hash_alg, TPM2_ALG.SHA256) self.assertEqual(cb_digest, b"\x01" * 32) self.assertEqual(cb_policyref, b"\x02" * 32) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLAUTH, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_polauthnv_callback(self): pol = { "description": "this is a polauthnv policy", "policy": [ { "type": "authorizenv", "nvPublic": { "nvIndex": 0x1000000, "nameAlg": "SHA256", "attributes": { "PPWRITE": 0, "OWNERWRITE": 0, "AUTHWRITE": 1, "POLICYWRITE": 0, "POLICY_DELETE": 0, "WRITELOCKED": 0, "WRITEALL": 0, "WRITEDEFINE": 0, "WRITE_STCLEAR": 0, "GLOBALLOCK": 0, "PPREAD": 0, "OWNERREAD": 0, "AUTHREAD": 1, "POLICYREAD": 0, "NO_DA": 0, "ORDERLY": 0, "CLEAR_STCLEAR": 0, "READLOCKED": 0, "WRITTEN": 1, "PLATFORMCREATE": 0, "READ_STCLEAR": 0, "TPM2_NT": "ORDINARY", }, "authPolicy": "", "dataSize": 34, }, }, ], } polstr = json.dumps(pol) session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) nvp = TPMS_NV_PUBLIC( nvIndex=0x1000000, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=34, ) nvh = self.ectx.nv_define_space(None, TPM2B_NV_PUBLIC(nvp)) self.ectx.nv_write(nvh, b"\x00\x0b" + b"\x00" * 32) cb_nv_public = None cb_hash_alg = None def polauthnv_cb(nv_public, hash_alg): nonlocal cb_nv_public, cb_hash_alg cb_nv_public = nv_public cb_hash_alg = hash_alg cb_name = None def auth_cb(name): nonlocal cb_name, nvh cb_name = name return (nvh, nvh, ESYS_TR.PASSWORD) with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLAUTHNV, polauthnv_cb) p.set_callback(policy_cb_types.EXEC_AUTH, auth_cb) p.execute(self.ectx, session) self.assertEqual(cb_nv_public.nvIndex, nvp.nvIndex) self.assertEqual(cb_nv_public.nameAlg, nvp.nameAlg) self.assertEqual(cb_nv_public.attributes, nvp.attributes | TPMA_NV.WRITTEN) self.assertEqual(cb_nv_public.dataSize, nvp.dataSize) self.assertEqual(cb_hash_alg, TPM2_ALG.SHA256) self.assertEqual( cb_name, b"\x00\x0bx\x7f\x8a\xa5&\xdbK\xf2L\x97\x8by\x92\x1f\xf4*\xae\xe6E\xa1\x15\xfb|\x05]\xed\xd4\x9f\xc3\xb5\xd1\xf6", ) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_AUTH, auth_cb) p.set_callback(policy_cb_types.EXEC_POLAUTHNV, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_poldup_callback(self): pol = { "description": "this is a poldup policy", "policy": [ {"type": "duplicationselect", "newParentPath": "new parent path"}, ], } polstr = json.dumps(pol) session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) cb_path = None def poldup_cb(): return TPM2B_NAME(b"\x12" * 32) def public_cb(path): nonlocal cb_path cb_path = path return TPMT_PUBLIC.parse("rsa2048") with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PUBLIC, public_cb) p.set_callback(policy_cb_types.EXEC_POLDUP, poldup_cb) p.execute(self.ectx, session) dig2b = self.ectx.policy_get_digest(session) self.assertEqual(cb_path, b"new parent path") self.assertEqual( dig2b, b"\xfdk\xa5z\x00)\xf9>vb\x8e\xcf\xfex\x91\x1d\xf5\xc9<\xc2N]S\xe0dr\xe0\xc3\xdd\x11nv", ) def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.CALC_PUBLIC, public_cb) p.set_callback(policy_cb_types.EXEC_POLDUP, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") def test_exec_polaction_callback(self): pol = { "description": "this is a polaction policy", "policy": [{"type": "action", "action": "this is an action"}], } polstr = json.dumps(pol) session = self.ectx.start_auth_session( ESYS_TR.NONE, ESYS_TR.NONE, TPM2_SE.POLICY, TPMT_SYM_DEF(algorithm=TPM2_ALG.NULL), TPM2_ALG.SHA256, ) cb_action = None def polaction_cb(action): nonlocal cb_action cb_action = action with policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLACTION, polaction_cb) p.execute(self.ectx, session) self.assertEqual(cb_action, b"this is an action") def bad_cb(*args): raise Exception("callback exception") with self.assertRaises(Exception) as e, policy(polstr, TPM2_ALG.SHA256) as p: p.set_callback(policy_cb_types.EXEC_POLACTION, bad_cb) p.execute(self.ectx, session) self.assertEqual(str(e.exception), "callback exception") tpm2-pytss-3.0.0-rc0/test/test_tcti.py000066400000000000000000000152151506405471500176040ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest from tpm2_pytss import * from .TSS2_BaseTest import TSS2_EsapiTest class MyTCTI(PyTCTI): def __init__(self, subtcti, magic=None): self._tcti = subtcti self._is_finalized = False self._error = None if magic is not None: super().__init__(magic=magic) else: super().__init__() @property def is_finalized(self): return self._is_finalized def do_transmit(self, command): self._tcti.transmit(command) def do_receive(self, timeout): return self._tcti.receive() def do_cancel(self): self._tcti.cancel() def do_get_poll_handles(self): return self._tcti.get_poll_handles() def do_set_locality(self, locality): self._tcti.set_locality(locality) def do_make_sticky(self, handle, is_sticky): if self._tcti is not None: self._tcti.make_sticky(handle, is_sticky) if self._error is not None: raise self._error def do_finalize(self): self._is_finalized = True if self._error is not None: raise self._error class TestTCTI(TSS2_EsapiTest): def test_init(self): self.assertEqual(self.tcti.version, 2) self.assertGreater(int.from_bytes(self.tcti.magic, "big"), 0) v1ctx = ffi.cast("TSS2_TCTI_CONTEXT_COMMON_V1 *", self.tcti._ctx) v1ctx.version = 1 tcti = TCTI(self.tcti._ctx) self.assertEqual(tcti.version, 1) self.assertEqual(tcti._v2, None) def test_transmit_receive(self): startup = b"\x80\x01\x00\x00\x00\x0C\x00\x00\x01\x44\x00\x00" self.tcti.transmit(startup) resp = self.tcti.receive() self.assertEqual(resp, b"\x80\x01\x00\x00\x00\n\x00\x00\x01\x00") def test_finalize(self): tcti = TCTI(self.tcti._ctx) tcti.finalize() def test_cancel(self): if getattr(self.tcti, "name", "") == "swtpm": self.skipTest("cancel not supported by swtpm") startup = b"\x80\x01\x00\x00\x00\x0C\x00\x00\x01\x44\x00\x00" self.tcti.transmit(startup) self.tcti.cancel() def test_get_poll_handles(self): tcti_name = getattr(self.tcti, "name", "") try: self.tcti.get_poll_handles() except TSS2_Exception as e: if e.rc != lib.TSS2_TCTI_RC_NOT_IMPLEMENTED: raise e else: self.skipTest(f"get_poll_handles not supported by {tcti_name}") def test_set_locality(self): self.tcti.set_locality(TPMA_LOCALITY.TWO) def test_make_sticky(self): tcti_name = getattr(self.tcti, "name", "") if tcti_name in ("swtpm", "mssim"): self.skipTest(f"make_sticky not supported by {tcti_name}") self.tcti.make_sticky(0, 0) tcti._v2 = None with self.assertRaises(RuntimeError) as e: self.tcti.make_sticky(0, 0) self.assertEqual(str(e.exception), "unsupported by TCTI API version") def test_tctildr(self): self.assertIsInstance(self.tcti.name, str) self.assertIsInstance(self.tcti.conf, str) with self.assertRaises(TypeError): TCTILdr(name=None, conf=1234) with self.assertRaises(TypeError): TCTILdr(name=1234, conf=None) def test_custom_pytcti_esapi(self): t = MyTCTI(self.tcti) e = ESAPI(t) e.get_random(4) e.startup(TPM2_SU.CLEAR) def test_custom_pytcti_C_wrapper_transmit_receive(self): t = MyTCTI(self.tcti) # Go through the C API directly and call transmit and recv t.transmit(b"\x80\x01\x00\x00\x00\x0C\x00\x00\x01\x44\x00\x00") resp = t.receive(-1) self.assertEqual(resp, b"\x80\x01\x00\x00\x00\n\x00\x00\x01\x00") def test_custom_pytcti_cancel(self): if getattr(self.tcti, "name", "") == "swtpm": self.skipTest("cancel not supported by swtpm") t = MyTCTI(self.tcti) t.transmit(b"\x80\x01\x00\x00\x00\x0C\x00\x00\x01\x44\x00\x00") t.cancel() def test_custom_pytcti_finalize(self): t = MyTCTI(self.tcti) t.finalize() self.assertTrue(t.is_finalized) def test_custom_pytcti_get_poll_handles(self): tcti_name = getattr(self.tcti, "name", "") t = MyTCTI(self.tcti) try: handles = t.get_poll_handles() for h in handles: self.assertTrue(isinstance(h, PollData)) except TSS2_Exception as e: if e.rc != lib.TSS2_TCTI_RC_NOT_IMPLEMENTED: raise e else: self.skipTest(f"get_poll_handles not supported by {tcti_name}") def test_custom_pytcti_set_locality(self): t = MyTCTI(self.tcti) t.set_locality(TPMA_LOCALITY.TWO) def test_custom_pytcti_make_sticky(self): t = MyTCTI(None) t._error = None t.make_sticky(0, 0) t.make_sticky(0, 1) t.make_sticky(0, False) # Test that throwing an exception shows the originating exception t._error = RuntimeError("Bills Error") with self.assertRaises(RuntimeError, msg="Bills Error"): t.make_sticky(5, True) t._v2 = None with self.assertRaises(TSS2_Exception): t.make_sticky(0, 0) def test_custom_pytcti_version(self): t = MyTCTI(None) self.assertEqual(t.version, 2) def test_custom_pytcti_magic(self): t = MyTCTI(None) magic = b"PYTCTI\x00\x00" self.assertEqual(t.magic, magic) # max magic len magic = b"THISISIT" t = MyTCTI(None, magic) self.assertEqual(t.magic, magic) # small magic len magic = b"COOL" t = MyTCTI(None, magic) self.assertEqual(t.magic, magic) # min magic magic = b"" t = MyTCTI(None, magic) self.assertEqual(t.magic, magic) with self.assertRaises(ValueError): MyTCTI(None, b"THISISTOOBIG") def test_custom_pytcti_ctx_manager_finalize(self): with MyTCTI(self.tcti) as t: e = ESAPI(t) r = e.get_random(4) self.assertEqual(len(r), 4) e.startup(TPM2_SU.CLEAR) self.assertTrue(t.is_finalized) def test_custom_pytcti_finalize_error(self): t = MyTCTI(self.tcti) t._error = RuntimeError("Bills Error 2") with self.assertRaises(RuntimeError, msg="Bills Error 2"): t.finalize() def test_is_available(self): self.assertTrue(TCTILdr.is_available()) self.assertFalse(TCTILdr.is_available("this-tcti-doesnt-exist")) if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_tcti_spi_helper.py000066400000000000000000000112341506405471500220130ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest from tpm2_pytss import * try: from tpm2_pytss.TCTISPIHelper import TCTISPIHelper except NotImplementedError: raise unittest.SkipTest("TCTISPIHelper not supported, skipping.") class MySPITcti(TCTISPIHelper): TPM_DID_VID_HEAD = 0 TPM_DID_VID_BODY = 1 TPM_ACCESS_HEAD = 2 TPM_ACCESS_BODY = 3 TPM_STS_HEAD = 4 TPM_STS_BODY = 5 TPM_RID_HEAD = 6 TPM_RID_BODY = 7 TPM_DID_VID_0 = b"\x83\xd4\x0f\00\xd1\x15\x1b\x00" TPM_ACCESS_0 = b"\x80\xd4\x00\x00\xa1" TPM_STS_0 = b"\x83\xd4\x00\x18\x40\x00\x00\x00" TPM_RID_0 = b"\x80\xd4\x0f\x04\x00" def __init__(self, *args, with_exception=None, **kwargs): # Example of setting userdata, can be anything. You want # bound to this class, you can even add arguments, etc. self.with_exception = with_exception self.tpm_state = MySPITcti.TPM_DID_VID_HEAD # call the superclass super().__init__(*args, **kwargs) def on_sleep_ms(self, milliseconds: int) -> None: pass def on_start_timeout(self, milliseconds: int) -> None: pass def on_timeout_expired(self) -> bool: return True def on_spi_transfer(self, data_in: bytes) -> bytes: if self.with_exception: raise self.with_exception if self.waitstate: if self.tpm_state == MySPITcti.TPM_DID_VID_HEAD: b = bytearray(MySPITcti.TPM_DID_VID_0[:4]) b[3] |= 0x01 elif self.tpm_state == MySPITcti.TPM_DID_VID_BODY: b = MySPITcti.TPM_DID_VID_0[4:] elif self.tpm_state == MySPITcti.TPM_ACCESS_HEAD: b = bytearray(MySPITcti.TPM_ACCESS_0[:4]) b[3] |= 0x01 elif self.tpm_state == MySPITcti.TPM_ACCESS_BODY: b = MySPITcti.TPM_ACCESS_0[4:] elif self.tpm_state == MySPITcti.TPM_STS_HEAD: b = bytearray(MySPITcti.TPM_STS_0[:4]) b[3] |= 0x01 elif self.tpm_state == MySPITcti.TPM_STS_BODY: b = MySPITcti.TPM_STS_0[4:] elif self.tpm_state == MySPITcti.TPM_RID_HEAD: b = bytearray(MySPITcti.TPM_RID_0[:4]) b[3] |= 0x01 elif self.tpm_state == MySPITcti.TPM_RID_BODY: b = MySPITcti.TPM_RID_0[4:] else: raise RuntimeError("BAD STATE") self.tpm_state += 1 else: if self.tpm_state == MySPITcti.TPM_DID_VID_HEAD: b = MySPITcti.TPM_DID_VID_0 elif self.tpm_state == MySPITcti.TPM_ACCESS_HEAD: b = MySPITcti.TPM_ACCESS_0 elif self.tpm_state == MySPITcti.TPM_STS_HEAD: b = MySPITcti.TPM_STS_0 elif self.tpm_state == MySPITcti.TPM_RID_HEAD: b = MySPITcti.TPM_RID_0 else: raise RuntimeError("BAD STATE") self.tpm_state += 2 return bytes(b) def on_spi_acquire(self) -> None: pass def on_spi_release(self) -> None: pass class MyBadSPITcti(TCTISPIHelper): def on_sleep_ms(self, milliseconds: int) -> None: pass def on_start_timeout(self, milliseconds: int) -> None: pass def on_timeout_expired(self) -> bool: return True def on_spi_transfer(self, data_in: bytes) -> bytes: pass class MyBadSPITcti2(TCTISPIHelper): def on_sleep_ms(self, milliseconds: int) -> None: pass def on_start_timeout(self, milliseconds: int) -> None: pass def on_timeout_expired(self) -> bool: return True def on_spi_transfer(self, data_in: bytes) -> bytes: pass def on_spi_acquire(self) -> None: pass class TestTCTI(unittest.TestCase): def test_spi_helper_good(self): MySPITcti() def yest_spi_helper_good_wait_state(self): MySPITcti(with_wait_state=True) def test_MyBadSPITcti(self): with self.assertRaises(NotImplementedError): MyBadSPITcti(with_wait_state=True) def test_MyBadSPITcti2(self): with self.assertRaises(NotImplementedError): MyBadSPITcti2(with_wait_state=True) def test_init_baseclase(self): with self.assertRaises(NotImplementedError): TCTISPIHelper() def test_init_baseclase_with_wait_state(self): with self.assertRaises(NotImplementedError): TCTISPIHelper(with_wait_state=True) def test_with_exception_accross_c(self): with self.assertRaises(RuntimeError, msg="foobar"): MySPITcti(with_exception=RuntimeError("foobar")) if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_tsskey.py000066400000000000000000000107431506405471500201640ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-3 from tpm2_pytss import * from tpm2_pytss.tsskey import TSSPrivKey, _parent_rsa_template, _parent_ecc_template from .TSS2_BaseTest import TSS2_EsapiTest from asn1crypto.core import ObjectIdentifier from asn1crypto import pem import unittest rsa_pem = b"""-----BEGIN TSS2 PRIVATE KEY----- MIIB8gYGZ4EFCgEDoAMBAQECBEAAAAEEggEYARYAAQALAAYEcgAAABAAEAgAAAEA AQEAzF/VFhLaIJ9Y3up8slssYhV1Fhh7KwYBCR1dqLeI9QkDF6M05b/Uc589yMsn WVIheHnkEEXyo+rD6q12BpDrC9nS6G11hd9e5TPAibVOAvt8jY3C6/b0JGCFpMNq W69ZonwSPO+aMPXogRBk2OL/jeost9IFbcJjEkwIs5rcaF4sI8wOXTXAx8rrqp0B aUjbZz1OJl9PxyCtizLPtdzfCoHVVu9FDrncKpSV1GuGWV6QCTAi8ln1KnRUdmnF YBltollhuZ5CLQRekfDdiPkm9ez2Ii/sbes2UvX3vSbyrI1WWCoNqeanSMDSvuMF CEBd8i5YDXhAYLcSu/shWZlvPQSBwAC+ACBvkTiYshUXeUbh6Sp+9uSw1RsgGNSf 3BrApTSK5XtGEAAQUjLH4kLMJSC2c2KXRW/H9o9tuhafEX3VwlutMcz3AW+3m/gq MHGtezT22Oy+jImy2n1NiFotqF/3xZr6WD9IrrJh9MKhWZfucOgCpTclo7P3OaAX pCz81gA+sZ1NvvOLHL/ULNcKPcltDOHmI1ag6rhz1vQIq3r7Wd71RI5a/gUGxPCx RmxDJYOlsFlR3mG/MiqSSB6dZ67H/Q== -----END TSS2 PRIVATE KEY----- """ class TSSKeyTest(TSS2_EsapiTest): def test_rsa_frompem(self): TSSPrivKey.from_pem(rsa_pem) def test_rsa_topem(self): key = TSSPrivKey.from_pem(rsa_pem) pem = key.to_pem() self.assertEqual(pem, rsa_pem) def test_create_load_rsa(self): key = TSSPrivKey.create_rsa(self.ectx) key.load(self.ectx) def test_create_load_ecc(self): key = TSSPrivKey.create_ecc(self.ectx) key.load(self.ectx) def test_create_load_ecc_password(self): key = TSSPrivKey.create_ecc(self.ectx, password=b"1234") key.load(self.ectx, password=b"1234") def test_create_password_load_no_password(self): key = TSSPrivKey.create_ecc(self.ectx, password=b"1234") with self.assertRaises(RuntimeError) as e: key.load(self.ectx) self.assertEqual(str(e.exception), "no password specified but it is required") def test_create_no_password_load_password(self): key = TSSPrivKey.create_ecc(self.ectx) with self.assertWarns(UserWarning) as w: key.load(self.ectx, password=b"1234") self.assertEqual(str(w.warning), "password specified but empty_auth is true") def test_persistent_parent_rsa(self): insens = TPM2B_SENSITIVE_CREATE() inpublic = TPM2B_PUBLIC(publicArea=_parent_rsa_template) parent, _, _, _, _ = self.ectx.create_primary(insens, inpublic) self.ectx.evict_control( ESYS_TR.RH_OWNER, parent, 0x81000081, session1=ESYS_TR.PASSWORD ) key = TSSPrivKey.create_rsa(self.ectx, parent=0x81000081) key.load(self.ectx) self.assertEqual(key.parent, 0x81000081) def test_persistent_parent_ecc(self): insens = TPM2B_SENSITIVE_CREATE() inpublic = TPM2B_PUBLIC(publicArea=_parent_ecc_template) parent, _, _, _, _ = self.ectx.create_primary(insens, inpublic) self.ectx.evict_control( ESYS_TR.RH_OWNER, parent, 0x81000081, session1=ESYS_TR.PASSWORD ) key = TSSPrivKey.create_ecc(self.ectx, parent=0x81000081) key.load(self.ectx) self.assertEqual(key.parent, 0x81000081) def test_bad_pem_type(self): bad_pem = rsa_pem.replace(b"TSS2", b"BORK") with self.assertRaises(TypeError) as e: TSSPrivKey.from_pem(bad_pem) self.assertEqual(str(e.exception), "unsupported PEM type") def test_bad_oid(self): _, _, der = pem.unarmor(rsa_pem) dc = TSSPrivKey._tssprivkey_der.load(der) dc["type"] = ObjectIdentifier("1.2.3.4") badder = dc.dump() with self.assertRaises(TypeError) as e: TSSPrivKey.from_der(badder) self.assertEqual(str(e.exception), "unsupported key type") def test_no_ecc(self): cap_data = TPMS_CAPABILITY_DATA() cap_data.data.algorithms[0] = TPMS_ALG_PROPERTY(alg=TPM2_ALG.RSA) def mock_getcap(*args, **kwargs): return (False, cap_data) self.ectx.get_capability = mock_getcap TSSPrivKey.create_ecc(self.ectx) def test_no_ecc_no_rsa(self): cap_data = TPMS_CAPABILITY_DATA() def mock_getcap(*args, **kwargs): return (False, cap_data) self.ectx.get_capability = mock_getcap with self.assertRaises(RuntimeError) as e: TSSPrivKey.create_ecc(self.ectx) self.assertEqual(str(e.exception), "Unable to find supported parent key type") if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_types.py000066400000000000000000002276451506405471500200210ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import itertools import unittest from tpm2_pytss import * from tpm2_pytss.internal.utils import _lib_version_atleast from base64 import b64decode rsa_parent_key = b"""-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0FeMzAfnskx8eZYICdqURfwRhcgAWHkanaDZQXAMsKyBwkov yso31lhQQpjghFv1hzxy9z9yvcE+7LnFWbTnhWH2PPYyR87iM6eaW9wGdaFLMX5R 8xbYG1ZJYsBOfiS4LauEHDYaAsYL9uv/5K0Dw2d/LSxzbv+9+EC3AomICZsf7m1B BVQNvtWHaPBHH+19JGtGRg8KRBWRqnrzrx6WwpGtmHVNPJwOr5hz3FtOWj99STKc oow5EIR44lrzg4dDcpyi4vWiustdZJm2j2iHKMfGu37r/mMDPjKNxY1YZQS5B8s5 lgxp76UBAfTm3mttyH1K79eoplgkA+qBglVqQQIDAQABAoIBAQCsA/0t4ED+x4Pm Z2dPq3bMqahWCqGuap79EncOPlNb87JXFiWLi5a6lMP/mHWXEs4P0GsjlPFJlqo7 jc5RmLmnORCzmJo/C6Nb/r/FpE55BKkuvhsvV+cp+v4wWJL2N58RphE3sbucGqR6 RLRMvETlKyinxZGxTdothFEV+TOmqT4c3YXUyxTZj74oh+ovl22xopehxz/g9QwK VdZa2bs9p5gxUeYlE3BQTt/YQAXDxPp2kTnWf8CjQ+f1YOlx+1OVJVaVPk5d3/8U 7CK5ljZoB5y11AYT11cxlqwphlF3ePJYIuTQHRldCO2Z7fv2GFJnVqKH+eu2/4AT 94RpHpyBAoGBAO1fOV0QL7ZQk0pJlY0yETrfZRkLcUM9lFzWnF8N/zfv4CcawZpw PvSU5tTSnF/aYJn94KSKeZ/CiIJog4metlHNIc6qZBVTvh3lOGndib9YjLQ0j/Ru gYITCMmffe74+RTD4yTmbCttoay3DzIX+rK9RMEg7SDRrHxmsWRoZzKpAoGBAOCx HfG+FiZgJdWkelOgSBWG+9tcNmKyV+1wLR0XDx+Ung/0IWfhov4im6sPKKmKOALk A2cKKkcByr57Y57oBS1oT8489G8rgR4hJlBZOU40N8HRLg+9FafFH5ObS29zUeis AP/wq2l8DOlWUfRN1W8+YzamyOdDIGdgtGn1tFHZAoGBAKjxQS6POqYTqwEQZjRc Eg9It/efQTmONm3tANZWa/Mv8uViEbENeoExCSknzMwb7O0s2BnDxNSD7AyEvjnQ kAqgaRNiCmFzfLhiUEhouIVLTLllP5/ElsAxM+vsbAENipnQ4XV92jb+jDcVAuew UWmtc6XQ/XSCRrUzkcXY2LohAoGAJiNqJcJSGClxwpWsfc1S7vR+g3lfcdk7u32y 6qEjXATp32Nc2DkgZWqSabKlAEIJx9PUEAVVr7/KHhLrkeloF5EBGsyV4NjNjcOq sTCz3WZXoHpVCy7ZIiT/exp872nvmUK42LiNH9aCioiwWHttovg/9uLQbxChy2pK tUGTXeECgYBYh3LsYNuWHpi2tW+cO3V4XP1AGBqZy3SDKD/Uk1jZPjEamkZCRDl2 9AGIGz0H+Ovfg8vzCgYj0E9KLlE63wjSsKajC+Z17+nwzvy9cFJJtqTq/7aR0niI DoDguNqFEpw/cs8Eccbh0K43ubpLXc7xKoLGe5CF1sxEOZpYnPbyoA== -----END RSA PRIVATE KEY----- """ from cryptography.hazmat.primitives.serialization import ( load_pem_private_key, load_der_private_key, load_ssh_private_key, ) class TypesTest(unittest.TestCase): def test_TPML_PCR_SELECTION_parse_2_banks_all_friendly(self): pcr_sels = TPML_PCR_SELECTION.parse("sha1:3,4+sha256:all") self.assertEqual(pcr_sels.count, 2) self.assertEqual(pcr_sels.pcrSelections[0].hash, TPM2_ALG.SHA1) self.assertEqual(pcr_sels.pcrSelections[0].sizeofSelect, 3) # bits 3 and 4 should be set self.assertEqual(pcr_sels.pcrSelections[0].pcrSelect[0], (1 << 3 | 1 << 4)) self.assertEqual(pcr_sels.pcrSelections[0].pcrSelect[1], 0) self.assertEqual(pcr_sels.pcrSelections[0].pcrSelect[2], 0) self.assertEqual(pcr_sels.pcrSelections[0].pcrSelect[3], 0) self.assertEqual(pcr_sels.pcrSelections[1].hash, TPM2_ALG.SHA256) self.assertEqual(pcr_sels.pcrSelections[1].sizeofSelect, 3) # All bits should be set self.assertEqual(pcr_sels.pcrSelections[1].pcrSelect[0], 255) self.assertEqual(pcr_sels.pcrSelections[1].pcrSelect[1], 255) self.assertEqual(pcr_sels.pcrSelections[1].pcrSelect[2], 255) self.assertEqual(pcr_sels.pcrSelections[1].pcrSelect[3], 0) def test_TPML_PCR_SELECTION_parse_2_banks_mixed(self): pcr_sels = TPML_PCR_SELECTION.parse("sha256:16,17,18+0x0b:16,17,18") self.assertEqual(pcr_sels.count, 2) for i in range(0, pcr_sels.count): self.assertEqual(pcr_sels.pcrSelections[i].hash, TPM2_ALG.SHA256) self.assertEqual(pcr_sels.pcrSelections[i].sizeofSelect, 3) # bits 16, 17 and 18 should be set self.assertEqual(pcr_sels.pcrSelections[i].pcrSelect[0], 0) self.assertEqual(pcr_sels.pcrSelections[i].pcrSelect[1], 0) # offset by 16 since the third byte is index 16 to 24 inclusive self.assertEqual( pcr_sels.pcrSelections[i].pcrSelect[2], (1 << 0 | 1 << 1 | 1 << 2) ) self.assertEqual(pcr_sels.pcrSelections[i].pcrSelect[3], 0) def test_TPML_PCR_SELECTION_parse_None(self): pcr_sels = TPML_PCR_SELECTION.parse(None) self.assertEqual(pcr_sels.count, 0) def test_TPML_PCR_SELECTION_parse_empty_string(self): pcr_sels = TPML_PCR_SELECTION.parse("") self.assertEqual(pcr_sels.count, 0) def test_TPML_PCR_SELECTION_parse_plus_only(self): with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("+") def test_TPML_PCR_SELECTION_parse_plus_multiple(self): with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("+++") def test_TPML_PCR_SELECTION_parse_plus_unbalanced(self): with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("sha256:1+") with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("+sha256:1") with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("+sha256:1+") def test_TPML_PCR_SELECTION_parse_gibberish(self): with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("gibberish value") with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("foo+") with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("+bar") with self.assertRaises(ValueError): TPML_PCR_SELECTION.parse("sha256:1+bar") def test_TPML_PCR_SELECTION_from_TPMS_PCR_SELECTION_list(self): first = TPMS_PCR_SELECTION.parse("sha512:1, 7, 8, 12, 18, 24") second = TPMS_PCR_SELECTION.parse("sha384:all") third = TPMS_PCR_SELECTION.parse("sha1:1,3") pcr_sels = TPML_PCR_SELECTION(pcrSelections=[first, second, third]) self.assertEqual(pcr_sels.count, 3) x = pcr_sels.pcrSelections[0] self.assertEqual(x.hash, TPM2_ALG.SHA512) self.assertEqual(x.sizeofSelect, 3) self.assertEqual(x.pcrSelect[0], (1 << 1 | 1 << 7)) self.assertEqual(x.pcrSelect[1], (1 << 0 | 1 << 4)) self.assertEqual(x.pcrSelect[2], (1 << 2)) self.assertEqual(x.pcrSelect[3], (1 << 0)) x = pcr_sels.pcrSelections[1] self.assertEqual(x.hash, TPM2_ALG.SHA384) self.assertEqual(x.sizeofSelect, 3) # All bits should be set self.assertEqual(x.pcrSelect[0], 255) self.assertEqual(x.pcrSelect[1], 255) self.assertEqual(x.pcrSelect[2], 255) self.assertEqual(x.pcrSelect[3], 0) x = pcr_sels.pcrSelections[2] self.assertEqual(x.hash, TPM2_ALG.SHA1) self.assertEqual(x.sizeofSelect, 3) # All bits should be set self.assertEqual(x.pcrSelect[0], (1 << 1 | 1 << 3)) self.assertEqual(x.pcrSelect[1], 0) self.assertEqual(x.pcrSelect[2], 0) self.assertEqual(x.pcrSelect[3], 0) def test_TPMS_PCR_SELECTION(self): x = TPMS_PCR_SELECTION() self.assertEqual(x.hash, 0) self.assertEqual(x.sizeofSelect, 0) self.assertEqual(x.pcrSelect[0], 0) self.assertEqual(x.pcrSelect[1], 0) self.assertEqual(x.pcrSelect[2], 0) self.assertEqual(x.pcrSelect[3], 0) with self.assertRaises(ValueError) as e: TPMS_PCR_SELECTION(pcrs=(1, 2, 3)) self.assertEqual(str(e.exception), "hash and pcrs MUST be specified") x = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA256, sizeofSelect=2, pcrSelect=b"\xFF" * 2 ) self.assertEqual(x.hash, TPM2_ALG.SHA256) self.assertEqual(x.sizeofSelect, 2) self.assertEqual(x.pcrSelect[0], 0xFF) self.assertEqual(x.pcrSelect[1], 0xFF) self.assertEqual(x.pcrSelect[2], 0) self.assertEqual(x.pcrSelect[3], 0) def test_TPMS_PCR_SELECTION_parse(self): x = TPMS_PCR_SELECTION.parse("sha512:1, 7, 8, 12, 18, 24") self.assertEqual(x.hash, TPM2_ALG.SHA512) self.assertEqual(x.sizeofSelect, 3) self.assertEqual(x.pcrSelect[0], (1 << 1 | 1 << 7)) self.assertEqual(x.pcrSelect[1], (1 << 0 | 1 << 4)) self.assertEqual(x.pcrSelect[2], (1 << 2)) self.assertEqual(x.pcrSelect[3], (1 << 0)) def test_TPMS_PCR_SELECTION_parse_None(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse(None) def test_TPMS_PCR_SELECTION_parse_empty(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse("") def test_TPMS_PCR_SELECTION_parse_out_of_bounds_pcr(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse("sha256:42") def test_TPMS_PCR_SELECTION_parse_malformed(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse("this is gibberish") def test_TPMS_PCR_SELECTION_parse_only_colon(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse(":") def test_TPMS_PCR_SELECTION_parse_only_bank_and_colon(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse("sha256:") def test_TPMS_PCR_SELECTION_parse_bank_and_garbage(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse("sha256:foo") def test_TPMS_PCR_SELECTION_parse_multiple_colons(self): with self.assertRaises(ValueError): TPMS_PCR_SELECTION.parse(":::") def test_TPM2B_PUBLIC(self): # Test setting inPublic = TPM2B_PUBLIC() publicArea = inPublic.publicArea publicArea.type = TPM2_ALG.ECC inPublic.publicArea.type = TPM2_ALG.ECC inPublic.publicArea.nameAlg = TPM2_ALG.SHA1 inPublic.publicArea.objectAttributes = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ) inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = ( TPM2_ALG.SHA256 ) inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.curveID = TPM2_ECC.NIST_P256 # test getting self.assertEqual(publicArea.type, TPM2_ALG.ECC) self.assertEqual(inPublic.publicArea.nameAlg, TPM2_ALG.SHA1) self.assertEqual( inPublic.publicArea.objectAttributes, ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDSA ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg, TPM2_ALG.SHA256, ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.NULL ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.kdf.scheme, TPM2_ALG.NULL ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256 ) def test_TPM_OBJECT_init(self): pub = TPM2B_PUBLIC(publicArea=TPMT_PUBLIC(nameAlg=TPM2_ALG.SHA256)) self.assertEqual(pub.publicArea.nameAlg, TPM2_ALG.SHA256) with self.assertRaises( AttributeError, msg="TPM2B_PUBLIC has no field by the name of badfield" ): TPM2B_PUBLIC(badfield=1) def test_TPM_OBJECT_init_cdata(self): with self.assertRaises( TypeError, msg="Unexpected _cdata type uint8_t, expected TPM2B_DIGEST" ): TPM2B_DIGEST(_cdata=ffi.new("uint8_t *")) def test_TPM2_ALG_parse(self): self.assertEqual(TPM2_ALG.parse("sha"), TPM2_ALG.SHA) self.assertEqual(TPM2_ALG.parse("sha1"), TPM2_ALG.SHA1) self.assertEqual(TPM2_ALG.parse("sha256"), TPM2_ALG.SHA256) self.assertEqual(TPM2_ALG.parse("ShA384"), TPM2_ALG.SHA384) self.assertEqual(TPM2_ALG.parse("SHA512"), TPM2_ALG.SHA512) self.assertEqual(TPM2_ALG.parse("mgf1"), TPM2_ALG.MGF1) self.assertEqual(TPM2_ALG.parse("RSaes"), TPM2_ALG.RSAES) self.assertEqual(TPM2_ALG.parse("ECDH"), TPM2_ALG.ECDH) self.assertEqual(TPM2_ALG.parse("SHA3_512"), TPM2_ALG.SHA3_512) with self.assertRaises(ValueError): TPM2_ALG.parse("") with self.assertRaises(TypeError): TPM2_ALG.parse(None) with self.assertRaises(ValueError): TPM2_ALG.parse("foo") def test_TPM_FRIENDLY_INT_bad_to_string(self): with self.assertRaises(ValueError) as e: TPM2_ALG.to_string(TPM2_ALG.LAST + 1) self.assertEqual(str(e.exception), "Could not match 69 to class TPM2_ALG") def test_ESYS_TR(self): self.assertEqual(ESYS_TR.parse("PCR0"), ESYS_TR.PCR0) self.assertEqual(ESYS_TR.parse("NONE"), ESYS_TR.NONE) self.assertEqual(ESYS_TR.parse("LoCkout"), ESYS_TR.LOCKOUT) self.assertEqual(ESYS_TR.parse("owner"), ESYS_TR.OWNER) self.assertEqual(ESYS_TR.parse("NuLL"), ESYS_TR.NULL) self.assertEqual(ESYS_TR.to_string(ESYS_TR.OWNER), "ESYS_TR.OWNER") with self.assertRaises(ValueError): ESYS_TR.parse("") with self.assertRaises(TypeError): ESYS_TR.parse(None) with self.assertRaises(ValueError): ESYS_TR.parse("foo"), TPM2_ALG.SHA512 def test_TPM2_ECC(self): self.assertEqual(TPM2_ECC.parse("NONE"), TPM2_ECC.NONE) self.assertEqual(TPM2_ECC.parse("nist_p192"), TPM2_ECC.NIST_P192) self.assertEqual(TPM2_ECC.parse("BN_P256"), TPM2_ECC.BN_P256) self.assertEqual(TPM2_ECC.parse("sm2_P256"), TPM2_ECC.SM2_P256) with self.assertRaises(ValueError): TPM2_ECC.parse("") with self.assertRaises(TypeError): TPM2_ECC.parse(None) with self.assertRaises(ValueError): TPM2_ECC.parse("foo") def test_TPM2_CC(self): self.assertEqual(TPM2_CC.parse("NV_Increment"), TPM2_CC.NV_Increment) self.assertEqual(TPM2_CC.parse("PCR_Reset"), TPM2_CC.PCR_Reset) self.assertEqual(TPM2_CC.parse("Certify"), TPM2_CC.Certify) self.assertEqual(TPM2_CC.parse("UnSEAL"), TPM2_CC.Unseal) with self.assertRaises(ValueError): TPM2_CC.parse("") with self.assertRaises(TypeError): TPM2_CC.parse(None) with self.assertRaises(ValueError): TPM2_CC.parse("foo") def test_TPMA_OBJECT(self): self.assertEqual(TPMA_OBJECT.parse("FIXEDTPM"), TPMA_OBJECT.FIXEDTPM) self.assertEqual( TPMA_OBJECT.parse("ADMINwithPOLICY"), TPMA_OBJECT.ADMINWITHPOLICY ) self.assertEqual(TPMA_OBJECT.parse("SIGN_ENCRYPT"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("SIGN"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("ENCRYPT"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("sign"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("encrypt"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("siGN"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual(TPMA_OBJECT.parse("enCRYpt"), TPMA_OBJECT.SIGN_ENCRYPT) self.assertEqual( TPMA_OBJECT.parse("sign_encrypt|ADMINWITHPOLICY|fixedTPM"), ( TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.ADMINWITHPOLICY ), ) with self.assertRaises(ValueError): TPMA_OBJECT.parse("") with self.assertRaises(TypeError): TPMA_OBJECT.parse(None) with self.assertRaises(ValueError): TPMA_OBJECT.parse("foo") def test_TPMA_NV(self): self.assertEqual(TPMA_NV.parse("ppwrite"), TPMA_NV.PPWRITE) self.assertEqual(TPMA_NV.parse("ORDerlY"), TPMA_NV.ORDERLY) self.assertEqual(TPMA_NV.parse("NO_DA"), TPMA_NV.NO_DA) self.assertEqual( TPMA_NV.parse("ppwrite|orderly|NO_DA"), (TPMA_NV.PPWRITE | TPMA_NV.ORDERLY | TPMA_NV.NO_DA), ) self.assertEqual(TPMA_NV.parse("noda"), TPMA_NV.NO_DA) self.assertEqual(TPMA_NV.parse("NodA"), TPMA_NV.NO_DA) self.assertEqual(TPMA_NV.parse("NODA"), TPMA_NV.NO_DA) with self.assertRaises(ValueError): TPMA_NV.parse("") with self.assertRaises(TypeError): TPMA_NV.parse(None) with self.assertRaises(ValueError): TPMA_NV.parse("foo") self.assertEqual(str(TPMA_NV.NO_DA | TPM2_NT.COUNTER << 4), "noda|nt=0x1") self.assertEqual(TPMA_NV.parse("noda|nt=0x1").nt, TPM2_NT.COUNTER) with self.assertRaises(ValueError) as e: TPMA_NV.parse("madeup=1234") self.assertEqual(str(e.exception), "unknown mask type madeup") with self.assertRaises(ValueError) as e: TPMA_NV.parse("nt=0x10") self.assertEqual( str(e.exception), "value for nt is to large, got 0x10, max is 0xf" ) def test_TPM2_SPEC(self): self.assertEqual(TPM2_SPEC.parse("Family"), TPM2_SPEC.FAMILY) self.assertEqual(TPM2_SPEC.parse("Level"), TPM2_SPEC.LEVEL) self.assertEqual(TPM2_SPEC.parse("DAY_of_YEAR"), TPM2_SPEC.DAY_OF_YEAR) with self.assertRaises(ValueError): TPM2_SPEC.parse("") with self.assertRaises(TypeError): TPM2_SPEC.parse(None) with self.assertRaises(ValueError): TPM2_SPEC.parse("foo") def test_TPM2_GENERATED_VALUE(self): self.assertEqual(TPM2_GENERATED.parse("value"), TPM2_GENERATED.VALUE) with self.assertRaises(ValueError): TPM2_GENERATED.parse("") with self.assertRaises(TypeError): TPM2_GENERATED.parse(None) with self.assertRaises(ValueError): TPM2_GENERATED.parse("foo") def test_TPM2_RC(self): self.assertEqual(TPM2_RC.parse("Success"), TPM2_RC.SUCCESS) self.assertEqual(TPM2_RC.parse("HMAC"), TPM2_RC.HMAC) self.assertEqual(TPM2_RC.parse("NO_RESULT"), TPM2_RC.NO_RESULT) with self.assertRaises(ValueError): TPM2_RC.parse("") with self.assertRaises(TypeError): TPM2_RC.parse(None) with self.assertRaises(ValueError): TPM2_RC.parse("foo") def test_TPM2_EO(self): self.assertEqual(TPM2_EO.parse("EQ"), TPM2_EO.EQ) self.assertEqual(TPM2_EO.parse("unsigned_GT"), TPM2_EO.UNSIGNED_GT) self.assertEqual(TPM2_EO.parse("BITCLEAR"), TPM2_EO.BITCLEAR) with self.assertRaises(ValueError): TPM2_EO.parse("") with self.assertRaises(TypeError): TPM2_EO.parse(None) with self.assertRaises(ValueError): TPM2_EO.parse("foo") def test_TPM2_ST(self): self.assertEqual(TPM2_ST.parse("null"), TPM2_ST.NULL) self.assertEqual(TPM2_ST.parse("AUTH_SECRET"), TPM2_ST.AUTH_SECRET) self.assertEqual(TPM2_ST.parse("fu_manifest"), TPM2_ST.FU_MANIFEST) with self.assertRaises(ValueError): TPM2_ST.parse("") with self.assertRaises(TypeError): TPM2_ST.parse(None) with self.assertRaises(ValueError): TPM2_ST.parse("foo") def test_TPM2_SU(self): self.assertEqual(TPM2_SU.parse("clear"), TPM2_SU.CLEAR) self.assertEqual(TPM2_SU.parse("State"), TPM2_SU.STATE) with self.assertRaises(ValueError): TPM2_SU.parse("") with self.assertRaises(TypeError): TPM2_SU.parse(None) with self.assertRaises(ValueError): TPM2_SU.parse("foo") def test_TPM2_SE(self): self.assertEqual(TPM2_SE.parse("hmac"), TPM2_SE.HMAC) self.assertEqual(TPM2_SE.parse("TRiaL"), TPM2_SE.TRIAL) self.assertEqual(TPM2_SE.parse("POLICY"), TPM2_SE.POLICY) with self.assertRaises(ValueError): TPM2_SE.parse("") with self.assertRaises(TypeError): TPM2_SE.parse(None) with self.assertRaises(ValueError): TPM2_SE.parse("foo") def test_TPM2_PT(self): self.assertEqual(TPM2_PT.parse("none"), TPM2_PT.NONE) self.assertEqual(TPM2_PT.parse("GrouP"), TPM2_PT.GROUP) self.assertEqual(TPM2_PT.parse("FIXED"), TPM2_PT.FIXED) with self.assertRaises(ValueError): TPM2_PT.parse("") with self.assertRaises(TypeError): TPM2_PT.parse(None) with self.assertRaises(ValueError): TPM2_PT.parse("foo") def test_TPM2B_PUBLIC_specified_parts(self): attrs = ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ) templ = TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.parse("SHA1"), objectAttributes=attrs ) inPublic = TPM2B_PUBLIC(publicArea=templ) inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = ( TPM2_ALG.SHA256 ) inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL inPublic.publicArea.parameters.eccDetail.curveID = TPM2_ECC.NIST_P256 # test getting self.assertEqual(inPublic.publicArea.type, TPM2_ALG.ECC) self.assertEqual(inPublic.publicArea.nameAlg, TPM2_ALG.SHA1) self.assertEqual( inPublic.publicArea.objectAttributes, ( TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN ), ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDSA ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg, TPM2_ALG.SHA256, ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.NULL ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.kdf.scheme, TPM2_ALG.NULL ) self.assertEqual( inPublic.publicArea.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256 ) def test_marshal(self): pb = TPM2B_PUBLIC() pb.publicArea.authPolicy.buffer = b"password" b = pb.publicArea.authPolicy.marshal() self.assertEqual(b, b"\x00\x08password") def test_unmarshal(self): buf = b"\x00\x05test1" d, offset = TPM2B_DIGEST.unmarshal(buf) self.assertEqual(offset, 7) self.assertEqual(d.size, 5) db = d.buffer self.assertEqual(db, b"test1") name2b = TPM2B_NAME(b"\x00\x04" + b"\xAA" * 20) name, offset = TPMT_HA.unmarshal(name2b) self.assertEqual(offset, len(name2b)) self.assertEqual(name.hashAlg, TPM2_ALG.SHA1) self.assertEqual(bytes(name.digest.sha1), b"\xAA" * 20) def test_unsupported_unmarshal(self): with self.assertRaises(RuntimeError) as e: TPM_OBJECT.unmarshal(b"") self.assertEqual(str(e.exception), "No unmarshal function found for TPM_OBJECT") def test_TPMT_PUBLIC_empty(self): templ = TPMT_PUBLIC.parse() self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_rsa(self): templ = TPMT_PUBLIC.parse("rsa") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_rsa_rsapss(self): templ = TPMT_PUBLIC.parse( "rsa:rsapss:null", TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.RSAPSS) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA256 ) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_rsa_keysizes(self): for keysize in [1024, 2048, 3072, 4096]: templ = TPMT_PUBLIC.parse(f"rsa{keysize}") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, keysize) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual( templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL ) def test_TPMT_PUBLIC_parse_rsa2048_(self): templ = TPMT_PUBLIC.parse("rsa2048:") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_rsaall_all(self): rsasizes = [1024, 2048, 3072, 4096] keysizes = [128, 192, 256] modes = ["cfb", "cbc", "ofb", "ctr", "ecb"] for rsasize, keysize, mode in list( itertools.product(rsasizes, keysizes, modes) ): templ = TPMT_PUBLIC.parse( f"rsa{rsasize}:rsassa-sha384:aes{keysize}{mode}", TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.exponent, 0) self.assertEqual(templ.parameters.rsaDetail.keyBits, rsasize) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA384, ) self.assertEqual(templ.parameters.rsaDetail.symmetric.keyBits.aes, keysize) self.assertEqual( templ.parameters.rsaDetail.symmetric.mode.sym, TPM2_ALG.parse(mode) ) self.assertEqual( templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.AES ) def test_TPMT_PUBLIC_parse_rsa2048_restricted(self): templ = TPMT_PUBLIC.parse(alg="rsa2048", objectAttributes="RESTRICTED") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual(templ.objectAttributes, TPMA_OBJECT.RESTRICTED) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.rsaDetail.symmetric.keyBits.aes, 128) self.assertEqual(templ.parameters.rsaDetail.symmetric.mode.sym, TPM2_ALG.CFB) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.AES) def test_TPMT_PUBLIC_parse_bad_params(self): message = "Expected keybits for RSA to be one of ['1024', '2048', '3072', '4096'], got:\"512\"" with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse(alg="rsa512") message = "Expected bits to be one of ['128', '192', '256'], got: \"512\"" with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse(alg="rsa2048:aes512") message = "Expected mode to be one of ['cfb', 'cbc', 'ofb', 'ctr', 'ecb'], got: \"yyy\"" with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse(alg="rsa2048:aes256yyy") message = "Expected object prefix to be one of ('rsa', 'ecc', 'aes', 'camellia', 'xor', 'hmac', 'keyedhash'), got: \"unsupported\"" with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse("unsupported") message = 'Expected symmetric detail to be null or start with one of aes, camellia, got: "hmac"' with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse("rsa2048:hmac") message = 'Keyedhash objects cannot have asym detail, got: "aes128"' with self.assertRaises(ValueError, msg=message) as e: TPMT_PUBLIC.parse("hmac:aes128") def test_TPMT_PUBLIC_parse_ecc_ecdaa4_sha256(self): # scheme is set, so we need to be smarter about the attributes we use templ = TPMT_PUBLIC.parse( "ecc:ecdaa4-sha256", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.NIST_P256) self.assertEqual(templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDAA) self.assertEqual(templ.parameters.eccDetail.scheme.details.ecdaa.count, 4) self.assertEqual( templ.parameters.eccDetail.scheme.details.ecdaa.hashAlg, TPM2_ALG.SHA256 ) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA256 ) # since this was restricted it should set the symmetric details to aes128cfb self.assertEqual(templ.parameters.asymDetail.symmetric.keyBits.aes, 128) self.assertEqual(templ.parameters.asymDetail.symmetric.mode.sym, TPM2_ALG.CFB) self.assertEqual(templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES) def test_TPMT_PUBLIC_parse_ecc_ecdaa4(self): # scheme is set, so we need to be smarter about the attributes we use templ = TPMT_PUBLIC.parse( "ecc:ecdaa4", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.NIST_P256) self.assertEqual(templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDAA) self.assertEqual(templ.parameters.eccDetail.scheme.details.ecdaa.count, 4) self.assertEqual( templ.parameters.eccDetail.scheme.details.ecdaa.hashAlg, TPM2_ALG.SHA256 ) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA256 ) # since this was restricted it should set the symmetric details to aes128cfb self.assertEqual(templ.parameters.asymDetail.symmetric.keyBits.aes, 128) self.assertEqual(templ.parameters.asymDetail.symmetric.mode.sym, TPM2_ALG.CFB) self.assertEqual(templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES) def test_TPMT_PUBLIC_parse_ecda_ecdh_sha384(self): # scheme is set, so we need to be smarter about the attributes we use templ = TPMT_PUBLIC.parse( "ecc:ecdh-sha384", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.NIST_P256) self.assertEqual(templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDH) self.assertEqual( templ.parameters.eccDetail.scheme.details.ecdh.hashAlg, TPM2_ALG.SHA384 ) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA384 ) # since this was restricted it should set the symmetric details to aes128cfb self.assertEqual(templ.parameters.asymDetail.symmetric.keyBits.aes, 128) self.assertEqual(templ.parameters.asymDetail.symmetric.mode.sym, TPM2_ALG.CFB) self.assertEqual(templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES) def test_TPMT_PUBLIC_parse_ecda_ecdsa_ecdh_ecschnorr(self): # scheme is set, so we need to be smarter about the attributes we use for scheme in ["ecdsa", "ecdh", "ecschnorr"]: templ = TPMT_PUBLIC.parse( f"ecc:{scheme}", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual( templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.NIST_P256 ) self.assertEqual( templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.parse(scheme) ) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA256, ) # since this was restricted it should set the symmetric details to aes128cfb self.assertEqual(templ.parameters.asymDetail.symmetric.keyBits.aes, 128) self.assertEqual( templ.parameters.asymDetail.symmetric.mode.sym, TPM2_ALG.CFB ) self.assertEqual( templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES ) def test_TPMT_PUBLIC_parse_ecc_all(self): curves = ["192", "224", "256", "384", "521"] keysizes = [128, 192, 256] modes = ["cfb", "cbc", "ofb", "ctr", "ecb"] schemes = [ "ecdsa", "ecdh", "ecschnorr", "ecdsa-sha", "ecdh-sha384", "ecschnorr-sha512", ] for curve, keysize, mode, scheme in list( itertools.product(curves, keysizes, modes, schemes) ): templ = TPMT_PUBLIC.parse( f"ecc{curve}:{scheme}:aes{keysize}{mode}", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS, ) hunks = scheme.split("-") scheme = hunks[0] scheme_halg = TPM2_ALG.parse(hunks[1] if len(hunks) > 1 else "sha256") self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual( templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.parse(curve) ) self.assertEqual( templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.parse(scheme) ) self.assertEqual( templ.parameters.asymDetail.scheme.details.anySig.hashAlg, scheme_halg ) self.assertEqual(templ.parameters.asymDetail.symmetric.keyBits.aes, keysize) self.assertEqual( templ.parameters.asymDetail.symmetric.mode.sym, TPM2_ALG.parse(mode) ) self.assertEqual( templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.AES ) def test_TPMT_PUBLIC_parse_xor(self): templ = TPMT_PUBLIC.parse(alg="xor") self.assertEqual(templ.type, TPM2_ALG.KEYEDHASH) self.assertEqual(templ.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.XOR) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.hashAlg, TPM2_ALG.SHA256, ) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.kdf, TPM2_ALG.KDF1_SP800_108, ) templ = TPMT_PUBLIC.parse(alg="xor:sha512") self.assertEqual(templ.type, TPM2_ALG.KEYEDHASH) self.assertEqual(templ.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.XOR) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.hashAlg, TPM2_ALG.SHA512, ) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.exclusiveOr.kdf, TPM2_ALG.KDF1_SP800_108, ) def test_TPMT_PUBLIC_parse_keyedhash(self): templ = TPMT_PUBLIC.parse(alg="keyedhash") self.assertEqual(templ.type, TPM2_ALG.KEYEDHASH) self.assertEqual(templ.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.NULL) # should fail, cannot have additional specifiers with self.assertRaises(ValueError): TPMT_PUBLIC.parse(alg="keyedhash:sha512") def test_TPMT_PUBLIC_parse_hmac(self): templ = TPMT_PUBLIC.parse(alg="hmac") self.assertEqual(templ.type, TPM2_ALG.KEYEDHASH) self.assertEqual(templ.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.HMAC) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.hmac.hashAlg, TPM2_ALG.SHA256, ) templ = TPMT_PUBLIC.parse(alg="hmac:sha512") self.assertEqual(templ.type, TPM2_ALG.KEYEDHASH) self.assertEqual(templ.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.HMAC) self.assertEqual( templ.parameters.keyedHashDetail.scheme.details.hmac.hashAlg, TPM2_ALG.SHA512, ) def test_TPMT_PUBLIC_parse_ecc_plain(self): templ = TPMT_PUBLIC.parse(alg="ecc") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.NIST_P256) self.assertEqual(templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_ecc_sm2(self): templ = TPMT_PUBLIC.parse(alg="ecc_sm2") self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ.parameters.eccDetail.curveID, TPM2_ECC_CURVE.SM2_P256) self.assertEqual(templ.parameters.eccDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.asymDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPMT_PUBLIC_parse_ecc_camellia(self): templ = TPMT_PUBLIC.parse(alg="ecc:camellia128cfb") self.assertEqual( templ.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.CAMELLIA ) self.assertEqual(templ.parameters.eccDetail.symmetric.keyBits.camellia, 128) self.assertEqual( templ.parameters.eccDetail.symmetric.mode.camellia, TPM2_ALG.CFB ) def test_TPMT_PUBLIC_parse_ecc_sm4(self): templ = TPMT_PUBLIC.parse(alg="ecc:sm4128cfb") self.assertEqual(templ.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.SM4) self.assertEqual(templ.parameters.eccDetail.symmetric.keyBits.camellia, 128) self.assertEqual( templ.parameters.eccDetail.symmetric.mode.camellia, TPM2_ALG.CFB ) def test_TPMT_PUBLIC_parse_rsa_oaep(self): templ = TPMT_PUBLIC.parse( "rsa2048:oaep-sha512", nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ^ TPMA_OBJECT.SIGN_ENCRYPT, ) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.OAEP) self.assertEqual( templ.parameters.asymDetail.scheme.details.oaep.hashAlg, TPM2_ALG.SHA512 ) self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) def test_TPMT_PUBLIC_parse_rsa_rsaes(self): templ = TPMT_PUBLIC.parse( "rsa2048:rsaes", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ^ TPMA_OBJECT.SIGN_ENCRYPT, ) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.RSAES) def test_TPMT_PUBLIC_parse_camellia(self): templ = TPMT_PUBLIC.parse("camellia256cfb") self.assertEqual(templ.type, TPM2_ALG.SYMCIPHER) self.assertEqual(templ.parameters.symDetail.sym.algorithm, TPM2_ALG.CAMELLIA) self.assertEqual(templ.parameters.symDetail.sym.keyBits.sym, 256) self.assertEqual(templ.parameters.symDetail.sym.mode.sym, TPM2_ALG.CFB) def test_TPMT_PUBLIC_parse_sm4(self): templ = TPMT_PUBLIC.parse("sm4128cfb") self.assertEqual(templ.type, TPM2_ALG.SYMCIPHER) self.assertEqual(templ.parameters.symDetail.sym.algorithm, TPM2_ALG.SM4) self.assertEqual(templ.parameters.symDetail.sym.keyBits.sym, 128) self.assertEqual(templ.parameters.symDetail.sym.mode.sym, TPM2_ALG.CFB) with self.assertRaises(ValueError) as e: TPMT_PUBLIC.parse("sm4256cfb") self.assertEqual(str(e.exception), 'Expected bits to be 128, got: "256"') def test_TPML_ALG_parse_none(self): with self.assertRaises(ValueError): TPML_ALG.parse(None) def test_TPML_ALG_parse_empty(self): with self.assertRaises(ValueError): TPML_ALG.parse("") def test_TPML_ALG_parse_commas(self): with self.assertRaises(ValueError): TPML_ALG.parse(",,,,,,") def test_TPML_ALG_parse_single(self): a = TPML_ALG.parse("rsa") self.assertEqual(len(a), 1) self.assertEqual(a[0], TPM2_ALG.RSA) def test_TPML_ALG_parse_double(self): a = TPML_ALG.parse("rsa,aes") self.assertEqual(len(a), 2) self.assertEqual(a[0], TPM2_ALG.RSA) self.assertEqual(a[1], TPM2_ALG.AES) def test_TPML_ALG_parse_double_spaces(self): a = TPML_ALG.parse(" rsa , aes") self.assertEqual(len(a), 2) self.assertEqual(a[0], TPM2_ALG.RSA) self.assertEqual(a[1], TPM2_ALG.AES) def test_TPML_ALG_parse_double_mixed_case(self): a = TPML_ALG.parse("RSa,aEs") self.assertEqual(len(a), 2) self.assertEqual(a[0], TPM2_ALG.RSA) self.assertEqual(a[1], TPM2_ALG.AES) def test_TPML_ALG_parse_double_extra_commas(self): a = TPML_ALG.parse(",RSa,,aEs,,") self.assertEqual(len(a), 2) self.assertEqual(a[0], TPM2_ALG.RSA) self.assertEqual(a[1], TPM2_ALG.AES) def test_TPML_ALG_parse_bad(self): with self.assertRaises(ValueError): TPML_ALG.parse("not,real,alg") with self.assertRaises(ValueError): TPML_ALG.parse("jfghsjhdgfdhg") with self.assertRaises(ValueError): TPML_ALG.parse("aes,rsa,foo") def test_TPML_ALG_setitem_single(self): t = TPML_ALG() t[0] = TPM2_ALG.AES t[2] = TPM2_ALG.CAMELLIA t[8] = TPM2_ALG.ECDH self.assertEqual(t[0], TPM2_ALG.AES) self.assertEqual(t[2], TPM2_ALG.CAMELLIA) self.assertEqual(t[8], TPM2_ALG.ECDH) self.assertEqual(len(t), 9) def test_TPML_ALG_setitem_slices(self): t = TPML_ALG() t[0:4] = [TPM2_ALG.AES, TPM2_ALG.CAMELLIA, TPM2_ALG.ECDH, TPM2_ALG.ECMQV] self.assertEqual(t[0], TPM2_ALG.AES) self.assertEqual(t[1], TPM2_ALG.CAMELLIA) self.assertEqual(t[2], TPM2_ALG.ECDH) self.assertEqual(t[3], TPM2_ALG.ECMQV) self.assertEqual(len(t), 4) def test_TPML_ALG_setitem_slices_with_step(self): t = TPML_ALG() t[0:4:2] = [TPM2_ALG.AES, TPM2_ALG.ECDH] self.assertEqual(t[0], TPM2_ALG.AES) self.assertEqual(t[1], 0) self.assertEqual(t[2], TPM2_ALG.ECDH) self.assertEqual(t[3], 0) self.assertEqual(len(t), 4) def test_TPML_ALG_setitem_slices_with_too_many_unpack(self): t = TPML_ALG() with self.assertRaises(ValueError): t[0:4:2] = [TPM2_ALG.AES, TPM2_ALG.ECDH, TPM2_ALG.CAMELLIA] def test_TPML_ALG_setitem_slices_with_too_few_unpack(self): t = TPML_ALG() with self.assertRaises(ValueError): t[0:4:2] = [TPM2_ALG.AES] def test_TPML_ALG_setitem_slices_set_list_with_int_key(self): t = TPML_ALG() with self.assertRaises(TypeError): t[0] = [TPM2_ALG.AES] def test_TPML_PCR_SELECTION_setattr_slice(self): t = TPML_PCR_SELECTION() x = [ TPMS_PCR_SELECTION.parse("sha256:1,2,3"), TPMS_PCR_SELECTION.parse("sha384:0,5,6"), TPMS_PCR_SELECTION.parse("sha512:7"), ] t[0:3] = x self.assertEqual(t[0].hash, TPM2_ALG.SHA256) self.assertEqual(t[0].pcrSelect[0], 14) self.assertEqual(t[1].hash, TPM2_ALG.SHA384) self.assertEqual(t[1].pcrSelect[0], 97) self.assertEqual(t[2].hash, TPM2_ALG.SHA512) self.assertEqual(t[2].pcrSelect[0], 128) self.assertEqual(len(t), 3) def test_TPML_PCR_SELECTION_iterator(self): pcrselections = TPML_PCR_SELECTION.parse("sha256:1,2,3+sha384:0,5,6+sha512:7") self.assertEqual(len(pcrselections), 3) for i, selection in enumerate(pcrselections): if i == 0: self.assertEqual(selection.hash, TPM2_ALG.SHA256) self.assertEqual(selection.pcrSelect[0], 14) elif i == 1: self.assertEqual(selection.hash, TPM2_ALG.SHA384) self.assertEqual(selection.pcrSelect[0], 97) elif i == 2: self.assertEqual(selection.hash, TPM2_ALG.SHA512) self.assertEqual(selection.pcrSelect[0], 128) # make sure state resets for i, selection in enumerate(pcrselections): if i == 0: self.assertEqual(selection.hash, TPM2_ALG.SHA256) self.assertEqual(selection.pcrSelect[0], 14) elif i == 1: self.assertEqual(selection.hash, TPM2_ALG.SHA384) self.assertEqual(selection.pcrSelect[0], 97) elif i == 2: self.assertEqual(selection.hash, TPM2_ALG.SHA512) self.assertEqual(selection.pcrSelect[0], 128) def test_TPML_PCR_SELECTION_bad_selections(self): toomany = "+".join([f"{x}" for x in range(0, 17)]) with self.assertRaises( ValueError, msg="PCR Selection list greater than 16, got 17" ): TPML_PCR_SELECTION.parse(toomany) def test_TPM2B_AUTH_empty(self): x = TPM2B_AUTH() self.assertEqual(x.size, 0) def test_TPM2B_AUTH_bad_fields(self): with self.assertRaises(AttributeError): TPM2B_AUTH(foo="bar") def test_TPM2B_AUTH_empty_str(self): x = TPM2B_AUTH("") self.assertEqual(x.size, 0) def test_TPM2B_AUTH_set_str(self): # You can send it in as a string x = TPM2B_AUTH("password") self.assertEqual(x.size, 8) # but you get bytes back self.assertEqual(x.buffer, b"password") self.assertEqual(bytes(x), b"password") def test_TPMS_SENSITIVE_CREATE_with_string(self): x = TPMS_SENSITIVE_CREATE(userAuth="password") p = str(x.userAuth) self.assertEqual(p, binascii.hexlify("password".encode()).decode()) def test_TPM2B_SIMPLE_OBJECT(self): bob = b"bunchofbytes" dig = TPM2B_NAME(bob) self.assertEqual(dig.name, bob) self.assertEqual(len(dig), len(bob)) for i in range(0, len(dig)): self.assertEqual(dig[i], bob[i]) with self.assertRaises(IndexError): dig[len(dig)] self.assertEqual(dig[0:3], b"bun") self.assertEqual(dig[60:64], b"") with self.assertRaises(TypeError): dig["str"] i = 0 for b in dig: self.assertEqual(b, bob[i]) i = i + 1 b = bytes(dig) self.assertEqual(b, bob) self.assertEqual(dig, bob) self.assertNotEqual(dig, "pinchofbytes") sdig = TPM2B_DIGEST(bob) self.assertEqual(dig, sdig) with self.assertRaises(AttributeError): dig.size = 1 with self.assertRaises(TypeError): dig.name[0] = b"\x00" with self.assertRaises(AttributeError) as e: TPM2B_DIGEST(size=12) self.assertEqual(str(e.exception), "size is read only") # This checks that TPM2B_SIMPLE_OBJECTs __setattr__ calls TPM_OBJECTs __setattr__ dig.nosuchfield = b"1234" self.assertEqual(dig.nosuchfield, b"1234") def test_TPMS_ECC_POINT(self): x = b"12345678" y = b"87654321" t = TPMS_ECC_POINT(x=x, y=y) self.assertEqual(bytes(t.x), x) self.assertEqual(bytes(t.y), y) self.assertEqual(len(t.x), len(x)) self.assertEqual(len(t.y), len(y)) self.assertEqual(str(t.x), binascii.hexlify(x).decode()) self.assertEqual(str(t.y), binascii.hexlify(y).decode()) x = "thisisareallylongstringx" y = "thisisareallylongstringy" t = TPMS_ECC_POINT(x=x, y=y) self.assertEqual(bytes(t.x), x.encode()) self.assertEqual(bytes(t.y), y.encode()) self.assertEqual(len(t.x), len(x.encode())) self.assertEqual(len(t.y), len(y.encode())) self.assertEqual(str(t.x), binascii.hexlify(x.encode()).decode()) self.assertEqual(str(t.y), binascii.hexlify(y.encode()).decode()) x = b"12345678" y = b"87654321" t = TPMS_ECC_POINT() t.x = x t.y = y self.assertEqual(bytes(t.x), x) self.assertEqual(bytes(t.y), y) self.assertEqual(len(t.x), len(x)) self.assertEqual(len(t.y), len(y)) self.assertEqual(str(t.x), binascii.hexlify(x).decode()) self.assertEqual(str(t.y), binascii.hexlify(y).decode()) def test_scalar_data(self): x = b"12345678" y = b"87654321" t = TPM2B_ECC_POINT(TPMS_ECC_POINT(x=x, y=y)) TPM2B_ECC_POINT(t.point) def test_copy_constructor(self): x = b"12345678" y = b"87654321" t1 = TPM2B_ECC_POINT(TPMS_ECC_POINT(x=x, y=y)) t2 = TPM2B_ECC_POINT(t1) self.assertEqual(bytes(t1.point.x), bytes(t2.point.x)) self.assertEqual(bytes(t1.point.y), bytes(t2.point.y)) self.assertNotEqual(t1._cdata, t2._cdata) templ = TPMT_PUBLIC.parse(alg="ecc") templ2 = TPMT_PUBLIC(templ) self.assertEqual(templ.type, TPM2_ALG.ECC) self.assertEqual(templ2.type, TPM2_ALG.ECC) templ.type = TPM2_ALG.RSA self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ2.type, TPM2_ALG.ECC) templ2.type = TPM2_ALG.KEYEDHASH self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ2.type, TPM2_ALG.KEYEDHASH) def test_TPM_FRIENDLY_INT_iterator(self): self.assertNotEqual(len(list(TPM2_CC)), 0) def test_TPM_FRIENDLY_INT_contains(self): self.assertIn(TPM2_CC.AC_Send, TPM2_CC) def test_TPM2B_PUBLIC_parse(self): tpm2b = TPM2B_PUBLIC.parse("rsa") templ = tpm2b.publicArea self.assertEqual(templ.nameAlg, TPM2_ALG.SHA256) self.assertEqual( templ.objectAttributes, TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.type, TPM2_ALG.RSA) self.assertEqual(templ.parameters.rsaDetail.keyBits, 2048) self.assertEqual(templ.parameters.asymDetail.scheme.scheme, TPM2_ALG.NULL) self.assertEqual(templ.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) def test_TPML_DIGEST_VALUES(self): sha1 = b"0123456789abcdeffedc" sha256 = b"0123456789abcdeffedcba9876543210" digests = TPML_DIGEST_VALUES( [ TPMT_HA(hashAlg=TPM2_ALG.SHA1, digest=TPMU_HA(sha1=sha1)), TPMT_HA(hashAlg=TPM2_ALG.SHA256, digest=TPMU_HA(sha256=sha256)), ] ) self.assertEqual(len(digests), 2) self.assertEqual(digests[0].hashAlg, TPM2_ALG.SHA1) self.assertEqual(bytes(digests[0].digest.sha1), sha1) self.assertEqual(digests[1].hashAlg, TPM2_ALG.SHA256) self.assertEqual(bytes(digests[1].digest.sha256), sha256) def test_TPML_DIGEST(self): x = TPML_DIGEST([b"0123456789ABCDEF0123456789ABCDEF"]) self.assertEqual(len(x), 1) self.assertEqual(x[0], b"0123456789ABCDEF0123456789ABCDEF") x = TPML_DIGEST( [ "0123456789ABCDEF0123456789ABCDEF", b"12345678901234567890", TPM2B_DIGEST(b"0123456"), ] ) self.assertEqual(len(x), 3) self.assertEqual(x[0], b"0123456789ABCDEF0123456789ABCDEF") self.assertEqual(x[1], b"12345678901234567890") self.assertEqual(x[2], b"0123456") with self.assertRaises(TypeError): TPML_DIGEST([object(), object()]) with self.assertRaises(TypeError): TPML_DIGEST(TPML_ALG_PROPERTY()) with self.assertRaises(TypeError): TPML_PCR_SELECTION(TPML_AC_CAPABILITIES()) def test_TPMA_LOCALITY(self): self.assertEqual(TPMA_LOCALITY.create_extended(0), 32) self.assertEqual(TPMA_LOCALITY.create_extended(2), 34) self.assertEqual(TPMA_LOCALITY.create_extended(255 - 32), 255) with self.assertRaises(ValueError): TPMA_LOCALITY.create_extended(255 - 32 + 1) loc = TPMA_LOCALITY.parse("zero|four") self.assertEqual(loc, TPMA_LOCALITY.ZERO | TPMA_LOCALITY.FOUR) self.assertEqual(str(loc), "zero|four") loc = TPMA_LOCALITY.parse("240") self.assertEqual(loc, 240) self.assertEqual(str(loc), "0xf0") def test_TPMS_CONTEXT_from_tools(self): test_ctx = b"""utzA3gAAAAFAAAABgAAAAAAAAAAAAAOkAvIAAAAAAqIAIFNJEhgwU8zxMhuTBhSqPktXguCbMgUg mACnGHIlDr0mAn7QtSMsTy1hAOqPvR8LRxcCphVs1owzQuHIe1Ez4kwA5xSl2zU+xFMhuD9coN4Z LiRxwuxCDuQ41rqJHRpRbJKn0zj3uw/rpdkGzSKP70VlZxtTnH1TKnpA65Dhxmzt9+AqCC8oAbeT 8ceZy9FelFZJjKQ8ik8zavDLxhy5etD4Y9IwetM6rAt6tlUqzNeR2OhJMpn3uFt4eO+qLxCifIHR hgpD0+ulWoCXfYA2CJIPnnHGzxx96soUyXwng7rb4fgfWaan6SXfxd/MAcRQNAR7nVsG2wTyZH3F cVOqXaQhdZOBXsbsoZfPu3Vne3GGc9kA6V2RuhwvTVHYj3R5eCS+9eOknsr8dHWez8Txzwk1l5lx xLt2AmDO7M8IyHGcI68ven5/SoXEX3nwz8mlYHLhdPnuq11GO0Ak3cARCvfvKrZIPUF+Bhkk9HHg 725rbsSvWWi/Od+zWWqMKMX9um+PmT+xrA65+xBH0pYhv8UhYUqzEQc7eUylxXXQuQzGHTjL3XdL Rl9zo+WBjuBzF44E6j8c8ghdlUqCWICF/gfD8Nnfx2JT+rRcs1sz4+T3s8725ghYWmJhb+Oy+KDB PZQvl9F8XUpEZ3b+xJ0qBHhdhutFvqAFq2dTZLLy+sfOj61PPgz8hmCZcuc+i3OnA+73E7GXqucU YzRgJaptxRrMbujvIKlK/BI0OK4mGA505hLb+EjWkZ7eTkEmEyviVL5ZxeqPk3+hMArjuEy25HCN N7Js0AVEQzgXAQm5jdxkcNcwTR0Z46sDdntMkxslR//+0iep9EvcXLgZ/hyTkTjQkB7zKQjh3NBO r+ShbNtNnOUGnAYOhak3DMmOKdpBgAAAgAAA/wAWAAR53X6WF4cq4euj360A2EG67P+iZgAAAAEA JgAlAAQAAwByAAAABgCAABAAFIrV77jm23RSbSe0b3NqvEBvuN35""" test_session = b"""utzA3gAAAAIDAAu63MDeAAAAAUAAAAcDAAAAAAAAAAAAAp8BkwAAAAABGwAg3+5wcQDG7hmg8aaC g94E+NcznuqznZiXkmGiTHEL9AMA99ZtPnyRs1VxIGHVZcJJJyTyYmRO8bZAyXPPwq4fy8kkwqwv 0PE+S0UaVvmLA31rM5WhDryFIGp4CsCD+omQdwKNRhOHYLSmKLnvnIaA/ARauSFfl76+fpSTQRsG OtHQO19livPgPBCXQhfUxKWVCN0N9Wf0QXSIzj9djnk5/hQPDZ/GnoRkq22gZ8QgViS5xZ2U5kN3 kF8pKLv5onlTlT3NleY6G3BWBwZ6oERS3WSkaquDO5H/soA4YOx7y4UuLpIz/hgsFrf9j7vyGYcY JkkNOi6i0+hWpmDFnhn0gwZL6h+dJNd0qJIv5R7bjcnW7b4sJ5gaQPwAAAMAAAAABAMAAAAAAAAD AAAAAAAAABAACwAAAwEAIMn6hieIgUZusbUvHkdT+fB6m7Nor7v/p4MunwkyviTNACCFA6yl1FMW Oi6NOltEBFNSgQDnMCUgvgxixgL0nVUlcwAAAAAAAAAAAAAAAAAAAAA=""" ctxbytes = b64decode(test_ctx) ctx = TPMS_CONTEXT.from_tools(ctxbytes) self.assertEqual(ctx.hierarchy, lib.TPM2_RH_OWNER) self.assertEqual(ctx.savedHandle, 0x80000000) self.assertEqual(ctx.sequence, 932) self.assertEqual(ctx.contextBlob, ctxbytes[26:]) badmagic = bytearray(ctxbytes) badmagic[0] = 1 with self.assertRaises(ValueError): TPMS_CONTEXT.from_tools(badmagic) badversion = bytearray(ctxbytes) badversion[5] = 0xFF with self.assertRaises(ValueError): TPMS_CONTEXT.from_tools(badversion) sessbytes = b64decode(test_session) sess = TPMS_CONTEXT.from_tools(sessbytes) self.assertEqual(sess.hierarchy, TPM2_RH.NULL) self.assertEqual(sess.savedHandle, 0x03000000) self.assertEqual(sess.sequence, 671) self.assertEqual(sess.contextBlob, sessbytes[37:]) def test_TPM_FRIENDLY_INT_str(self): alg = TPM2_ALG(TPM2_ALG.ECC) self.assertEqual(str(alg), "ecc") badalg = TPM2_ALG(TPM2_ALG.LAST + 1) self.assertEqual(str(badalg), str(TPM2_ALG.LAST + 1)) def test_TPM_FRIENDLY_INTLIST_str(self): attrs = TPMA_OBJECT( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.SIGN_ENCRYPT ) self.assertEqual(str(attrs), "noda|decrypt|sign") badattrs = TPMA_OBJECT( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.NODA | TPMA_OBJECT.SIGN_ENCRYPT | 0x00900000 ) with self.assertRaises(ValueError) as e: str(badattrs) self.assertEqual(str(e.exception), "unnmatched values left: 0x900000") aw = TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD self.assertEqual(str(aw), "authwrite|authread") self.assertEqual(str(TPMA_CC()), "") def test_TPM_FRIENDLY_INTLIST_math(self): ab = abs(TPM2_ALG.RSA) self.assertIsInstance(ab, TPM2_ALG) self.assertEqual(ab, TPM2_ALG.RSA) add = TPM2_ALG.ERROR + 1 self.assertIsInstance(add, TPM2_ALG) self.assertEqual(add, TPM2_ALG.RSA) a = TPMA_OBJECT.RESTRICTED & 0x10000 self.assertIsInstance(a, TPMA_OBJECT) self.assertEqual(a, TPMA_OBJECT.RESTRICTED) ceil = TPM2_ALG.RSA.__ceil__() self.assertIsInstance(ceil, TPM2_ALG) self.assertEqual(ceil, TPM2_ALG.RSA) dm = divmod(TPM2_ALG.ECC, TPM2_ALG.NULL) self.assertIsInstance(dm[0], TPM2_ALG) self.assertIsInstance(dm[1], TPM2_ALG) floor = TPM2_ALG.RSA.__floor__() self.assertIsInstance(floor, TPM2_ALG) self.assertEqual(floor, TPM2_ALG.RSA) floordiv = TPM2_ALG.ECC.__floordiv__(1) self.assertIsInstance(floordiv, TPM2_ALG) inv = ~TPM2_ALG.ECC self.assertIsInstance(inv, TPM2_ALG) self.assertEqual(inv, ~int(TPM2_ALG.ECC)) ls = TPM2_ALG.RSA << 1 self.assertIsInstance(ls, TPM2_ALG) mod = TPM2_ALG.ECC % 100 self.assertIsInstance(mod, TPM2_ALG) mul = TPM2_ALG.RSA * 2 self.assertIsInstance(mul, TPM2_ALG) neg = -TPM2_ALG.RSA self.assertIsInstance(neg, TPM2_ALG) o = TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.FIXEDTPM self.assertIsInstance(o, TPMA_OBJECT) self.assertEqual(o, 0x2 | 0x10000) pos = +TPM2_ALG.RSA self.assertIsInstance(pos, TPM2_ALG) p = TPM2_ALG.RSA**1 self.assertIsInstance(p, TPM2_ALG) radd = 1 + TPM2_ALG.NULL self.assertIsInstance(radd, TPM2_ALG) rand = 1 & TPM2_ALG.RSA self.assertIsInstance(rand, TPM2_ALG) rdv = divmod(1, TPM2_ALG.ECC) self.assertIsInstance(rdv[0], TPM2_ALG) self.assertIsInstance(rdv[1], TPM2_ALG) rfloordiv = 1 // TPM2_ALG.RSA self.assertIsInstance(rfloordiv, TPM2_ALG) rmod = 3 % TPM2_ALG.RSA self.assertIsInstance(rmod, TPM2_ALG) rmul = 1 * TPM2_ALG.RSA self.assertIsInstance(rmul, TPM2_ALG) r = round(TPM2_ALG.RSA) self.assertIsInstance(r, TPM2_ALG) rp = 2**TPM2_ALG.RSA self.assertIsInstance(rp, TPM2_ALG) rrs = 1 >> TPM2_ALG.RSA self.assertIsInstance(rrs, TPM2_ALG) rs = TPM2_ALG.RSA >> 1 self.assertIsInstance(rs, TPM2_ALG) rsub = 1 - TPM2_ALG.RSA self.assertIsInstance(rsub, TPM2_ALG) rdiv = 1 / TPM2_ALG.RSA self.assertIsInstance(rdiv, TPM2_ALG) sub = TPM2_ALG.RSA - 1 self.assertIsInstance(sub, TPM2_ALG) div = TPM2_ALG.RSA / 1 self.assertIsInstance(div, TPM2_ALG) def test_TPM_FRIENDLY_INT_type(self): self.assertIsInstance(TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS, TPMA_OBJECT) def test_TPM2_RC_decode(self): self.assertEqual(TPM2_RC.NV_LOCKED.decode(), "tpm:error(2.0): NV access locked") def test_TSS2_RC_decode(self): self.assertEqual( TSS2_RC.ESYS_RC_BAD_VALUE.decode(), "esapi:A parameter has a bad value" ) def test_TPMT_SENSITIVE_to_pem(self): priv = TPMT_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) pem = priv.to_pem(pub.publicArea) load_pem_private_key(pem, password=None) # with a password pem = priv.to_pem(pub.publicArea, password=b"foo") with self.assertRaises(TypeError): load_pem_private_key(pem, password=None) load_pem_private_key(pem, password=b"foo") def test_TPM2B_SENSITIVE_to_pem(self): priv = TPM2B_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) pem = priv.to_pem(pub.publicArea) load_pem_private_key(pem, password=None) # with a password pem = priv.to_pem(pub.publicArea, password=b"foo") with self.assertRaises(TypeError): load_pem_private_key(pem, password=None) load_pem_private_key(pem, password=b"foo") def test_TPMT_SENSITIVE_to_der(self): priv = TPMT_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) der = priv.to_der(pub.publicArea) load_der_private_key(der, password=None) def test_TPM2B_SENSITIVE_to_der(self): priv = TPM2B_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) der = priv.to_der(pub.publicArea) load_der_private_key(der, password=None) def test_TPMT_SENSITIVE_to_ssh(self): priv = TPMT_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) sshpem = priv.to_ssh(pub.publicArea) load_ssh_private_key(sshpem, password=None) def test_TPM2B_SENSITIVE_to_ssh(self): priv = TPM2B_SENSITIVE.from_pem(rsa_parent_key) pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) sshpem = priv.to_ssh(pub.publicArea) load_ssh_private_key(sshpem, password=None) def test_TPM2B_PUBLIC_from_pem_strings(self): pub = TPM2B_PUBLIC.from_pem( rsa_parent_key, objectAttributes="userwithauth|sign", scheme="rsapss", symmetric="aes128ecb", ) self.assertEqual( pub.publicArea.objectAttributes, (TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.SIGN_ENCRYPT), ) self.assertEqual( pub.publicArea.parameters.rsaDetail.scheme.scheme, TPM2_ALG.RSAPSS ) self.assertEqual(pub.publicArea.parameters.rsaDetail.symmetric.keyBits.aes, 128) self.assertEqual( pub.publicArea.parameters.rsaDetail.symmetric.mode.aes, TPM2_ALG.ECB ) def test_struct_type_map(self): pub = TPMT_PUBLIC(type=TPM2_ALG.RSA) self.assertEqual(pub.type, TPM2_ALG.RSA) self.assertIsInstance(pub.type, TPM2_ALG) ctx = TPMS_CONTEXT(savedHandle=0x40000000) self.assertEqual(ctx.savedHandle, TPM2_HANDLE(0x40000000)) self.assertIsInstance(ctx.savedHandle, TPM2_HANDLE) def test_list_type_map(self): algs = TPML_ALG((TPM2_ALG.SHA256,)) self.assertEqual(algs[0], TPM2_ALG.SHA256) self.assertIsInstance(algs[0], TPM2_ALG) hl = TPML_HANDLE((0x40000000,)) self.assertEqual(hl[0], TPM2_HANDLE(0x40000000)) self.assertIsInstance(hl[0], TPM2_HANDLE) def test_TPMA_CC(self): cca = TPMA_CC.NV | 0x1234 | (5 << TPMA_CC.CHANDLES_SHIFT) self.assertEqual(str(cca), "nv|commandindex=0x1234|chandles=0x5") pcca = TPMA_CC.parse("nv|commandindex=1234|chandles=5") self.assertEqual(pcca & TPMA_CC.NV, TPMA_CC.NV) self.assertEqual(pcca.commandindex, 1234) self.assertEqual(pcca.chandles, 5) ccs = str(TPMA_CC.NV | TPMA_CC.V) self.assertEqual(ccs, "nv|v") def test_TPMA_SESSION(self): x = TPMA_SESSION.CONTINUESESSION | TPMA_SESSION.DECRYPT y = str(x) self.assertEqual(y, "continuesession|decrypt") x = TPMA_SESSION.CONTINUESESSION | TPMA_SESSION.DECRYPT | 0x128 with self.assertRaises(ValueError): str(x) def test_TSS2_OBJECT(self): if not _lib_version_atleast("tss2-policy", "4.0.0"): self.skipTest("tss2-policy required") o = TSS2_OBJECT(handle=ESYS_TR.OWNER) self.assertEqual(o.handle, ESYS_TR.OWNER) self.assertIsInstance(o.handle, ESYS_TR) def test_TSS2_POLICY_PCR_SELECTIONS(self): if not _lib_version_atleast("tss2-policy", "4.0.0"): self.skipTest("tss2-policy required") select = TSS2_POLICY_PCR_SELECTIONS( pcr_select=TPMS_PCR_SELECT(sizeofSelect=1, pcrSelect=b"\xAA") ) self.assertEqual(select.pcr_select.sizeofSelect, 1) self.assertEqual(bytes(select.pcr_select.pcrSelect), b"\xAA\x00\x00\x00") selection = TSS2_POLICY_PCR_SELECTIONS( pcr_selection=TPML_PCR_SELECTION( ( TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA1, sizeofSelect=2, pcrSelect=b"\xBB\xBB" ), TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA256, sizeofSelect=3, pcrSelect=b"\xCC\xCC\xCC" ), ), ), ) self.assertEqual(selection.pcr_selection[0].hash, TPM2_ALG.SHA1) self.assertEqual(selection.pcr_selection[0].sizeofSelect, 2) self.assertEqual( bytes(selection.pcr_selection[0].pcrSelect), b"\xBB\xBB\x00\x00" ) self.assertEqual(selection.pcr_selection[1].hash, TPM2_ALG.SHA256) self.assertEqual(selection.pcr_selection[1].sizeofSelect, 3) self.assertEqual( bytes(selection.pcr_selection[1].pcrSelect), b"\xCC\xCC\xCC\x00" ) def test_TSS2_POLICY_PCR_SELECTION(self): if not _lib_version_atleast("tss2-policy", "4.0.0"): self.skipTest("tss2-policy required") s = TSS2_POLICY_PCR_SELECTION( type=TSS2_POLICY_PCR_SELECTOR.PCR_SELECT, selections=TSS2_POLICY_PCR_SELECTIONS( pcr_select=TPMS_PCR_SELECT(sizeofSelect=3, pcrSelect=b"\xFF\xFF\xFF") ), ) self.assertEqual(s.type, TSS2_POLICY_PCR_SELECTOR.PCR_SELECT) self.assertIsInstance(s.type, TSS2_POLICY_PCR_SELECTOR) self.assertEqual(s.selections.pcr_select.sizeofSelect, 3) self.assertEqual(bytes(s.selections.pcr_select.pcrSelect), b"\xFF\xFF\xFF\x00") def test_TPMT_SIGNATURE(self): ecdsa = TPMT_SIGNATURE(sigAlg=TPM2_ALG.ECDSA) ecdsa.signature.ecdsa.signatureR = b"\x52" * 32 ecdsa.signature.ecdsa.signatureS = b"\x53" * 32 ecbytes = bytes(ecdsa) self.assertEqual( ecbytes, b"0D\x02 RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\x02 SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS", ) rsa = TPMT_SIGNATURE(sigAlg=TPM2_ALG.RSAPSS) rsa.signature.rsapss.sig = b"RSA" * 85 rsabytes = bytes(rsa) self.assertEqual(rsabytes, b"RSA" * 85) hmac = TPMT_SIGNATURE(sigAlg=TPM2_ALG.HMAC) hmac.signature.hmac.hashAlg = TPM2_ALG.SHA256 hmac.signature.hmac.digest.sha256 = b"HMAC" * 8 hmacbytes = bytes(hmac) self.assertEqual(hmacbytes, b"HMAC" * 8) bad = TPMT_SIGNATURE(sigAlg=TPM2_ALG.NULL) with self.assertRaises(TypeError): bytes(bad) def test_TPMT_SYM_DEF_parse(self): t = TPMT_SYM_DEF.parse("xor") self.assertEqual(t.algorithm, TPM2_ALG.XOR) t = TPMT_SYM_DEF.parse("aes") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 128) self.assertEqual(t.mode.sym, TPM2_ALG.CFB) t = TPMT_SYM_DEF.parse("aes256") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 256) self.assertEqual(t.mode.sym, TPM2_ALG.CFB) t = TPMT_SYM_DEF.parse("aes256cbc") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 256) self.assertEqual(t.mode.sym, TPM2_ALG.CBC) with self.assertRaises(ValueError): TPMT_SYM_DEF.parse("aes256bad") def test_TPMT_SYM_DEF_OBJECT_parse(self): t = TPMT_SYM_DEF_OBJECT.parse("xor") self.assertEqual(t.algorithm, TPM2_ALG.XOR) t = TPMT_SYM_DEF_OBJECT.parse("aes") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 128) self.assertEqual(t.mode.sym, TPM2_ALG.CFB) t = TPMT_SYM_DEF_OBJECT.parse("aes256") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 256) self.assertEqual(t.mode.sym, TPM2_ALG.CFB) t = TPMT_SYM_DEF_OBJECT.parse("aes256cbc") self.assertEqual(t.algorithm, TPM2_ALG.AES) self.assertEqual(t.keyBits.sym, 256) self.assertEqual(t.mode.sym, TPM2_ALG.CBC) with self.assertRaises(ValueError): TPMT_SYM_DEF_OBJECT.parse("aes256bad") def test_bad_assigment(self): a = TPMT_SYM_DEF.parse("xor") b = TPM2B_PUBLIC() with self.assertRaises(TypeError): a.algorithm = b with self.assertRaises(TypeError): b.publicArea = a def test_constants_marshal(self): a = TPM2_CC.PolicySecret.marshal() b = TPM2_CC.PolicySecret.to_bytes(4, byteorder="big") self.assertEqual(a, b) a = TPM2_RH.OWNER.marshal() b = TPM2_RH.OWNER.to_bytes(4, byteorder="big") self.assertEqual(a, b) a = TPM2_ALG.SHA256.marshal() b = TPM2_ALG.SHA256.to_bytes(2, byteorder="big") self.assertEqual(a, b) with self.assertRaises(RuntimeError): ESYS_TR.PCR9.marshal() def test_constants_unmarshal(self): a = TPM2_CC.PolicySecret b = TPM2_CC.unmarshal(a.to_bytes(4, byteorder="big"))[0] self.assertEqual(a, b) a = TPM2_RH.SRK b = TPM2_RH.SRK.unmarshal(a.to_bytes(4, byteorder="big"))[0] self.assertEqual(a, b) a = TPM2_ALG.SHA256 b = TPM2_ALG.SHA256.unmarshal(a.to_bytes(2, byteorder="big"))[0] self.assertEqual(a, b) with self.assertRaises(RuntimeError): ESYS_TR.PCR9.unmarshal(b"") def test_tpm2_handle_marshal(self): handle_bytes = TPM2_HANDLE(0xFFFFFFFF).marshal() self.assertEqual(handle_bytes, b"\xFF\xFF\xFF\xFF") def test_tpm2_handle_unmarshal(self): handle, off = TPM2_HANDLE.unmarshal(b"\xFF\xFF\xFF\xFF") self.assertEqual(handle, 0xFFFFFFFF) self.assertEqual(off, 4) def test_union_marshal(self): dig = b"A" * 32 ha = TPMU_HA(sha256=dig) buf = ha.marshal(TPM2_ALG.SHA256) self.assertEqual(buf, dig) with self.assertRaises(TSS2_Exception) as e: ha.marshal(TPM2_ALG.LAST + 1) self.assertEqual(e.exception.rc, TSS2_RC.MU_RC_BAD_VALUE) def test_union_unmarshal(self): dig = b"A" * 32 ha, off = TPMU_HA.unmarshal(TPM2_ALG.SHA256, dig) self.assertEqual(bytes(ha.sha256), dig) self.assertEqual(off, len(dig)) with self.assertRaises(TSS2_Exception) as e: ha.unmarshal(TPM2_ALG.LAST + 1, dig) self.assertEqual(e.exception.rc, TSS2_RC.MU_RC_BAD_VALUE) def test_struct_equal(self): sel_one = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA1, sizeofSelect=3, pcrSelect=b"\xFF\xFF\xFF", ) sel_two = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA1, sizeofSelect=3, pcrSelect=b"\xFF\xFF\xFF", ) self.assertEqual(sel_one, sel_two) def test_struct_not_equal(self): sel_one = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA1, sizeofSelect=3, pcrSelect=b"\xFF\xFF\xFF", ) sel_two = TPMS_PCR_SELECTION( hash=TPM2_ALG.SHA1, sizeofSelect=3, pcrSelect=b"\xFF\xAA\xFF", ) self.assertNotEqual(sel_one, sel_two) def test_struct_not_equal_different_types(self): ticket_one = TPMT_TK_AUTH( tag=TPM2_ST.NULL, hierarchy=TPM2_RH.NULL, digest=b"falafel", ) ticket_two = TPMT_TK_VERIFIED( tag=TPM2_ST.NULL, hierarchy=TPM2_RH.NULL, digest=b"falafel", ) self.assertNotEqual(ticket_one, ticket_two) if __name__ == "__main__": unittest.main() tpm2-pytss-3.0.0-rc0/test/test_utils.py000066400000000000000000000727311506405471500200070ustar00rootroot00000000000000#!/usr/bin/python3 -u # SPDX-License-Identifier: BSD-2 import unittest from tpm2_pytss import * from tpm2_pytss.internal.crypto import ( _generate_seed, public_to_key, _get_alg, _get_digest, ) from tpm2_pytss.utils import * from tpm2_pytss.internal.templates import ek_template from .TSS2_BaseTest import TSS2_EsapiTest from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding from base64 import b64decode rsa_private_key = b""" -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAxU5SokcbkKjsgBGsQhBF70LM2yudAGPUiHbLObvNJSwDcN8L TNN1Cg1+Q4VWb/jkEFEUMCHce6Rqq3xu+kTsj+J1BVfBIkxcNr7TdDCsgNiA4BX+ kGo4W0Z5y9AGiJNb2jjim+BoYwY67fGNKv2FE3BFdWLSoQcbdDAjStLw3yJ+nhz4 Op6dJRTyu8XWxYJwXziIAHBcNFAM7ipT9Yypv5+wZ8FyQizzUj321DruGzOPPKdy ISbRYGeyq3s8oSlui+2zIiEOb428+OWzttgwz2jfwJ8NQGXTRp1Iw/L/xottZPkA Yobff75SOv7or+sHlMpkLjtuftEhdpWnPIjXXwIDAQABAoIBAHFplvgulXqujtsC zZhf0EM6i5SD2khKGfWjCygRelcemI+9tbogZksz/FsFfuz4DOgQIuGT5S+xD5uo +AWlrrD6Q7ehfKOhbvQM9nD4NYAOcu3b1qreU6yrswDjf43r3kVuo1tkP7yD7UWu ri2C8oZ854AVIOtssWw062RsIgavw5yYG7igUVehOxQPRfP6YezYI8qTYwUy1T2i SQMcRzT5Q8KZnfPzJFse255X55Zf5reKDEruFtIQtHZl+FeL4wjb2xSQfIXV4KFa zRGVRuNyBKLVG8TVwLZdmL4zRWG3gHoFcVCCaIOunhHbN8lqjDj35XOKqt7BBzNx UrOrX4kCgYEA66V3YzEc0qTdqlTza2Il/eM/XoQStitQLLykZ/+yPWAgDr0XXAtg atVctFU61sejXsd8zBxuBk2KrZ2dbrnzxszytiA2+pFzsY8g4XwA5+7Zs8yRrMAI S6jNuuOBjseK8PfuEaO8wNbJGYxoEJtOvBl1M/U5HreaJsahnnuFmA0CgYEA1lkW D+Xj/SEGZY2aPVGKYvtWYzzHBm2JKLh2GpG5RZheTqwFXo6XeG2G63ZkupH/pQOg QXMIk4Lb/y6XapulmnLXprTQRFv+6b7sLA8u5DAAWmjbrRNU+iEuxkaDnaoHjxxK SxCcg4jQPbNmC/YRh5DOaeNJm+19HGd+gj2HhhsCgYBdoyCvv8JOScjzeFJJ53Rl ULnLmvu8e7WeMU+7K7XuAZZ7hNQVdUfY6/OsjPmWgzn93ZNPoDRwOLvUhX8bkrS1 2JbRnDd8lfO9KLzOHPJXN2g2tCFm3d/uAKPPkbvXup8RZdOqGsBUeITsrAhmIPDG ee9CuDz8YcTVh7SNP1Q0uQKBgF88CZ9apudKiwsH1SW1WuULgqBo2oyykiQzgNXh NQ4E2rHdoC0Y8ZeiIjXvzmVOhOUOLV+m+oJ/u7svOjs1mGh86e+5mmck8KduGoSg 4lakNSP2PtQxKKpRn/ScU9HzP5SIH0ImyUNvwAYJ9ScPV06COhO11nifFd1O5lh7 egFNAoGAUb6hqU4FE8DO8raO+dwTZBZqrlOldF7/L8aK2Xp98jkwtUIU0WLlo3AX BWUSCMWPt/jlmVdZPb8jFkGTlkrpy8dSlZQ1oja8nlaxjXuSy57dYRVkDUGLfvsJ 1fG6ahkXCMzRx03YPkp2Yi/ZyRIdvlwKugQNPxx+qSWCauBvUY4= -----END RSA PRIVATE KEY----- """ rsa_public_key = b"""-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU5SokcbkKjsgBGsQhBF 70LM2yudAGPUiHbLObvNJSwDcN8LTNN1Cg1+Q4VWb/jkEFEUMCHce6Rqq3xu+kTs j+J1BVfBIkxcNr7TdDCsgNiA4BX+kGo4W0Z5y9AGiJNb2jjim+BoYwY67fGNKv2F E3BFdWLSoQcbdDAjStLw3yJ+nhz4Op6dJRTyu8XWxYJwXziIAHBcNFAM7ipT9Yyp v5+wZ8FyQizzUj321DruGzOPPKdyISbRYGeyq3s8oSlui+2zIiEOb428+OWzttgw z2jfwJ8NQGXTRp1Iw/L/xottZPkAYobff75SOv7or+sHlMpkLjtuftEhdpWnPIjX XwIDAQAB -----END PUBLIC KEY----- """ ecc_private_key = b""" -----BEGIN EC PRIVATE KEY----- MHcCAQEEIMJI9ujmlT/qftbXWlMwOSpkxiWLAbyIMWEFPOqTbXYMoAoGCCqGSM49 AwEHoUQDQgAEgO/tHxp/YOuP4wAV3w66C8JNiSHOKSAYtlNKSN4ZDI//wn0f7zBv Uc7FqaRPA9LL6k6C1YfdOi/yvTB7Y4Tgaw== -----END EC PRIVATE KEY----- """ ecc_public_key = b"""-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgO/tHxp/YOuP4wAV3w66C8JNiSHO KSAYtlNKSN4ZDI//wn0f7zBvUc7FqaRPA9LL6k6C1YfdOi/yvTB7Y4Tgaw== -----END PUBLIC KEY----- """ rsa_parent_key = b"""-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0FeMzAfnskx8eZYICdqURfwRhcgAWHkanaDZQXAMsKyBwkov yso31lhQQpjghFv1hzxy9z9yvcE+7LnFWbTnhWH2PPYyR87iM6eaW9wGdaFLMX5R 8xbYG1ZJYsBOfiS4LauEHDYaAsYL9uv/5K0Dw2d/LSxzbv+9+EC3AomICZsf7m1B BVQNvtWHaPBHH+19JGtGRg8KRBWRqnrzrx6WwpGtmHVNPJwOr5hz3FtOWj99STKc oow5EIR44lrzg4dDcpyi4vWiustdZJm2j2iHKMfGu37r/mMDPjKNxY1YZQS5B8s5 lgxp76UBAfTm3mttyH1K79eoplgkA+qBglVqQQIDAQABAoIBAQCsA/0t4ED+x4Pm Z2dPq3bMqahWCqGuap79EncOPlNb87JXFiWLi5a6lMP/mHWXEs4P0GsjlPFJlqo7 jc5RmLmnORCzmJo/C6Nb/r/FpE55BKkuvhsvV+cp+v4wWJL2N58RphE3sbucGqR6 RLRMvETlKyinxZGxTdothFEV+TOmqT4c3YXUyxTZj74oh+ovl22xopehxz/g9QwK VdZa2bs9p5gxUeYlE3BQTt/YQAXDxPp2kTnWf8CjQ+f1YOlx+1OVJVaVPk5d3/8U 7CK5ljZoB5y11AYT11cxlqwphlF3ePJYIuTQHRldCO2Z7fv2GFJnVqKH+eu2/4AT 94RpHpyBAoGBAO1fOV0QL7ZQk0pJlY0yETrfZRkLcUM9lFzWnF8N/zfv4CcawZpw PvSU5tTSnF/aYJn94KSKeZ/CiIJog4metlHNIc6qZBVTvh3lOGndib9YjLQ0j/Ru gYITCMmffe74+RTD4yTmbCttoay3DzIX+rK9RMEg7SDRrHxmsWRoZzKpAoGBAOCx HfG+FiZgJdWkelOgSBWG+9tcNmKyV+1wLR0XDx+Ung/0IWfhov4im6sPKKmKOALk A2cKKkcByr57Y57oBS1oT8489G8rgR4hJlBZOU40N8HRLg+9FafFH5ObS29zUeis AP/wq2l8DOlWUfRN1W8+YzamyOdDIGdgtGn1tFHZAoGBAKjxQS6POqYTqwEQZjRc Eg9It/efQTmONm3tANZWa/Mv8uViEbENeoExCSknzMwb7O0s2BnDxNSD7AyEvjnQ kAqgaRNiCmFzfLhiUEhouIVLTLllP5/ElsAxM+vsbAENipnQ4XV92jb+jDcVAuew UWmtc6XQ/XSCRrUzkcXY2LohAoGAJiNqJcJSGClxwpWsfc1S7vR+g3lfcdk7u32y 6qEjXATp32Nc2DkgZWqSabKlAEIJx9PUEAVVr7/KHhLrkeloF5EBGsyV4NjNjcOq sTCz3WZXoHpVCy7ZIiT/exp872nvmUK42LiNH9aCioiwWHttovg/9uLQbxChy2pK tUGTXeECgYBYh3LsYNuWHpi2tW+cO3V4XP1AGBqZy3SDKD/Uk1jZPjEamkZCRDl2 9AGIGz0H+Ovfg8vzCgYj0E9KLlE63wjSsKajC+Z17+nwzvy9cFJJtqTq/7aR0niI DoDguNqFEpw/cs8Eccbh0K43ubpLXc7xKoLGe5CF1sxEOZpYnPbyoA== -----END RSA PRIVATE KEY----- """ ec_parent_key = b"""-----BEGIN EC PRIVATE KEY----- MHcCAQEEIODZrhXcbRQDOZUmzvYIWtU04ubMA7xTYnzsMs/LhwRUoAoGCCqGSM49 AwEHoUQDQgAEojRWBjpOkP4pH2fM5hha7iJj4A9RfDcbJrGTd181UMoYvfM+8VuY Qa6C2sTmPHlvWopRgWslXt1JmxbBKwWf2Q== -----END EC PRIVATE KEY----- """ mkcred = b64decode( b""" utzA3gAAAAEALQAgu8GEn+x61T9fIjPLo1IDCqcuY8T8RlBfBxDjMsOxcXPhuSJQ vSN85wOdCwEASKiqHPf63bvAoM7xKrhfTay8uLsncUDiCLC6FRGvnRPrwPWlZlNi rZps3C5E5dGdqLJneewxBYvDk4WBhCGps94oTuuRutU1U48QM8Uu4QWHaqAX7SGm ZmsHVC8kJta9i3v6LxtDTx5I7JJEbrbckSqSL3K79S7yW+nAy3GWqxMmeMvinicW F1Baf21zl4pov69NaRBmdGAho8D4FcBhZVsBFlsag3Kev0EaiYNzifnuQOXfMkmh PgSNwG4oSwDu66TLu2WDhyYf3tAXJKTEmXFIwHWJQM6vy/j6ZO73t04ynVJ/GseV jUCgpbZ9Uv6UL/3DUu+VZEJU0YD0os2sZg== """ ) mkcred_id_object = b64decode( b""" ACC7wYSf7HrVP18iM8ujUgMKpy5jxPxGUF8HEOMyw7Fxc+G5IlC9I3znA50L """ ) mkcred_encrypted_secret = b64decode( b""" SKiqHPf63bvAoM7xKrhfTay8uLsncUDiCLC6FRGvnRPrwPWlZlNirZps3C5E5dGd qLJneewxBYvDk4WBhCGps94oTuuRutU1U48QM8Uu4QWHaqAX7SGmZmsHVC8kJta9 i3v6LxtDTx5I7JJEbrbckSqSL3K79S7yW+nAy3GWqxMmeMvinicWF1Baf21zl4po v69NaRBmdGAho8D4FcBhZVsBFlsag3Kev0EaiYNzifnuQOXfMkmhPgSNwG4oSwDu 66TLu2WDhyYf3tAXJKTEmXFIwHWJQM6vy/j6ZO73t04ynVJ/GseVjUCgpbZ9Uv6U L/3DUu+VZEJU0YD0os2sZg== """ ) ek_test_template = TPMT_PUBLIC( type=TPM2_ALG.KEYEDHASH, nameAlg=TPM2_ALG.SHA256, objectAttributes=TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.ADMINWITHPOLICY | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.SIGN_ENCRYPT, parameters=TPMU_PUBLIC_PARMS( keyedHashDetail=TPMS_KEYEDHASH_PARMS( scheme=TPMT_KEYEDHASH_SCHEME( scheme=TPM2_ALG.HMAC, details=TPMU_SCHEME_KEYEDHASH( hmac=TPMS_SCHEME_HASH(hashAlg=TPM2_ALG.SHA256), ), ) ), ), ) class TestUtils(TSS2_EsapiTest): def test_generate_seed_rsa(self): insens = TPM2B_SENSITIVE_CREATE() _, public, _, _, _ = self.ectx.create_primary(insens) _generate_seed(public.publicArea, b"test") public.publicArea.nameAlg = TPM2_ALG.LAST + 1 with self.assertRaises(ValueError) as e: _generate_seed(public.publicArea, b"test") self.assertEqual( str(e.exception), f"unsupported digest algorithm {TPM2_ALG.LAST + 1}" ) public.publicArea.type = TPM2_ALG.NULL with self.assertRaises(ValueError) as e: _generate_seed(public.publicArea, b"test") self.assertEqual(str(e.exception), f"unsupported key type: {TPM2_ALG.NULL}") def test_generate_seed_ecc(self): insens = TPM2B_SENSITIVE_CREATE() _, public, _, _, _ = self.ectx.create_primary(insens, "ecc") _generate_seed(public.publicArea, b"test") public.publicArea.nameAlg = TPM2_ALG.LAST + 1 with self.assertRaises(ValueError) as e: _generate_seed(public.publicArea, b"test") self.assertEqual( str(e.exception), f"unsupported digest algorithm {TPM2_ALG.LAST + 1}" ) def test_MakeCredential_rsa(self): insens = TPM2B_SENSITIVE_CREATE() phandle, parent, _, _, _ = self.ectx.create_primary(insens) private, public, _, _, _ = self.ectx.create(phandle, insens) credblob, secret = make_credential( parent, b"credential data", public.get_name() ) handle = self.ectx.load(phandle, private, public) certinfo = self.ectx.activate_credential(handle, phandle, credblob, secret) self.assertEqual(b"credential data", bytes(certinfo)) def test_MakeCredential_ecc(self): insens = TPM2B_SENSITIVE_CREATE() phandle, parent, _, _, _ = self.ectx.create_primary(insens, "ecc") private, public, _, _, _ = self.ectx.create(phandle, insens, "ecc") credblob, secret = make_credential( parent, b"credential data", public.get_name() ) handle = self.ectx.load(phandle, private, public) certinfo = self.ectx.activate_credential(handle, phandle, credblob, secret) self.assertEqual(b"credential data", bytes(certinfo)) def test_make_credential_ecc_camellia(self): self.skipIfAlgNotSupported(TPM2_ALG.CAMELLIA) insens = TPM2B_SENSITIVE_CREATE() phandle, parent, _, _, _ = self.ectx.create_primary( insens, "ecc:camellia128cfb" ) self.assertEqual( parent.publicArea.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.CAMELLIA, ) private, public, _, _, _ = self.ectx.create(phandle, insens, "ecc") credblob, secret = make_credential( parent, b"credential data", public.get_name() ) handle = self.ectx.load(phandle, private, public) certinfo = self.ectx.activate_credential(handle, phandle, credblob, secret) self.assertEqual(b"credential data", bytes(certinfo)) def test_make_credential_ecc_sm4(self): if _get_alg(TPM2_ALG.SM4) is None: self.skipTest("SM4 is not supported by the cryptography module") elif _get_digest(TPM2_ALG.SM3_256) is None: self.skipTest("SM3 is not supported by the cryptography module") self.skipIfAlgNotSupported(TPM2_ALG.SM3_256) self.skipIfAlgNotSupported(TPM2_ALG.SM4) insens = TPM2B_SENSITIVE_CREATE() templ = TPM2B_PUBLIC.parse("ecc:sm4128cfb", nameAlg=TPM2_ALG.SM3_256) phandle, parent, _, _, _ = self.ectx.create_primary(insens, templ) self.assertEqual( parent.publicArea.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.SM4 ) private, public, _, _, _ = self.ectx.create(phandle, insens, "ecc") credblob, secret = make_credential( parent, b"credential data", public.get_name() ) handle = self.ectx.load(phandle, private, public) certinfo = self.ectx.activate_credential(handle, phandle, credblob, secret) self.assertEqual(b"credential data", bytes(certinfo)) def test_Wrap_rsa(self): insens = TPM2B_SENSITIVE_CREATE() phandle, parent, _, _, _ = self.ectx.create_primary(insens) public = TPM2B_PUBLIC.from_pem(rsa_public_key) sensitive = TPM2B_SENSITIVE.from_pem(rsa_private_key) symdef = TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.AES) symdef.mode.sym = TPM2_ALG.CFB symdef.keyBits.sym = 128 enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"", symdef ) self.ectx.import_(phandle, enckey, public, duplicate, outsymseed, symdef) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"", None ) self.ectx.import_( phandle, enckey, public, duplicate, outsymseed, TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.NULL), ) def test_Wrap_ecc(self): insens = TPM2B_SENSITIVE_CREATE() phandle, parent, _, _, _ = self.ectx.create_primary(insens, "ecc") public = TPM2B_PUBLIC.from_pem(ecc_public_key) sensitive = TPM2B_SENSITIVE.from_pem(ecc_private_key) symdef = TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.AES) symdef.mode.sym = TPM2_ALG.CFB symdef.keyBits.sym = 128 enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"\xA1" * 16, symdef ) self.ectx.import_(phandle, enckey, public, duplicate, outsymseed, symdef) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"", None ) self.ectx.import_( phandle, enckey, public, duplicate, outsymseed, TPMT_SYM_DEF_OBJECT(algorithm=TPM2_ALG.NULL), ) def test_unwrap_rsa_parent_rsa_child(self): parent_priv = TPMT_SENSITIVE.from_pem(rsa_parent_key, password=None) parent = TPM2B_PUBLIC.from_pem( rsa_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) public = TPM2B_PUBLIC.from_pem(rsa_public_key) sensitive = TPM2B_SENSITIVE.from_pem(rsa_private_key) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"", None ) unwrapped_sensitive = unwrap( parent.publicArea, parent_priv, public, duplicate, outsymseed ) self.assertEqual(sensitive.marshal(), unwrapped_sensitive.marshal()) def test_unwrap_rsa_parent_rsa_child_outerwrap(self): symdef = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) parent_priv = TPMT_SENSITIVE.from_pem(rsa_parent_key) parent = TPM2B_PUBLIC.from_pem(rsa_parent_key, symmetric=symdef) public = TPM2B_PUBLIC.from_pem(rsa_public_key) sensitive = TPM2B_SENSITIVE.from_pem(rsa_private_key) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"\xA1" * 16, symdef ) unwrapped_sensitive = unwrap( parent.publicArea, parent_priv, public, duplicate, outsymseed, b"\xA1" * 16, symdef, ) self.assertEqual(sensitive.marshal(), unwrapped_sensitive.marshal()) def test_unwrap_ec_parent_rsa_child(self): parent_priv = TPMT_SENSITIVE.from_pem(ec_parent_key, password=None) parent = TPM2B_PUBLIC.from_pem( ec_parent_key, symmetric=TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), ) public = TPM2B_PUBLIC.from_pem(rsa_public_key) sensitive = TPM2B_SENSITIVE.from_pem(rsa_private_key) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"", None ) unwrapped_sensitive = unwrap( parent.publicArea, parent_priv, public, duplicate, outsymseed ) self.assertEqual(sensitive.marshal(), unwrapped_sensitive.marshal()) def test_unwrap_ec_parent_rsa_child_outerwrap(self): symdef = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) parent_priv = TPMT_SENSITIVE.from_pem(ec_parent_key, password=None) parent = TPM2B_PUBLIC.from_pem(ec_parent_key, symmetric=symdef) public = TPM2B_PUBLIC.from_pem(rsa_public_key) sensitive = TPM2B_SENSITIVE.from_pem(rsa_private_key) enckey, duplicate, outsymseed = wrap( parent.publicArea, public, sensitive, b"\xA1" * 16, symdef ) unwrapped_sensitive = unwrap( parent.publicArea, parent_priv, public, duplicate, outsymseed, b"\xA1" * 16, symdef, ) self.assertEqual(sensitive.marshal(), unwrapped_sensitive.marshal()) def test_tpm_export_rsa_child_rsa_parent_with_inner_key(self): # # Step 1 - Create a TPM object to duplicate # phandle = self.ectx.create_primary(None)[0] # Create the child key, note we need to be able to enter the DUP role which requires # a policy session. session = self.ectx.start_auth_session( tpm_key=ESYS_TR.NONE, bind=ESYS_TR.NONE, session_type=TPM2_SE.TRIAL, symmetric=TPMT_SYM_DEF( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), auth_hash=TPM2_ALG.SHA256, ) self.ectx.policy_auth_value(session) self.ectx.policy_command_code(session, TPM2_CC.Duplicate) policy_digest = self.ectx.policy_get_digest(session) self.ectx.flush_context(session) session = None in_pub = TPM2B_PUBLIC.parse( "rsa2048:aes128cfb", objectAttributes="userwithauth|restricted|decrypt|sensitivedataorigin", authPolicy=policy_digest, ) tpm_priv, tpm_pub = self.ectx.create(phandle, None, in_pub)[:2] chandle = self.ectx.load(phandle, tpm_priv, tpm_pub) # # Step 2 - Duplicate it under a parent where you control the key. The parent MUST be a storage parent. # sym = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) parent = TPM2B_PUBLIC.from_pem( ec_parent_key, objectAttributes=TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT, symmetric=sym, ) new_phandle = self.ectx.load_external(parent) session = self.ectx.start_auth_session( tpm_key=ESYS_TR.NONE, bind=ESYS_TR.NONE, session_type=TPM2_SE.POLICY, symmetric=TPMT_SYM_DEF( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ), auth_hash=TPM2_ALG.SHA256, ) self.ectx.policy_auth_value(session) self.ectx.policy_command_code(session, TPM2_CC.Duplicate) encryptionKey = b"is sixteen bytes" # this is wrap performed by the TPM enckey, duplicate, outsymseed = self.ectx.duplicate( chandle, new_phandle, encryptionKey, sym, session1=session ) # # Step 4 - unwrap with the new parent private key # parent_priv = TPMT_SENSITIVE.from_pem(ec_parent_key, password=None) unwrapped_sensitive = unwrap( parent.publicArea, parent_priv, tpm_pub, duplicate, outsymseed, encryptionKey, sym, ) # # Step 5, validate the key by signing with the private key and verifying with the # public from create # priv_key = private_to_key(unwrapped_sensitive.sensitiveArea, tpm_pub.publicArea) message = b"A message I want to sign" signature = priv_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256(), ) pub_key = public_to_key(tpm_pub.publicArea) pub_key.verify( signature, message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256(), ) def test_create_ek_ecc(self): nv_read = NVReadEK(self.ectx) _, ecc_template = create_ek_template("EK-ECC256", nv_read) _, ecc, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), ecc_template, ESYS_TR.ENDORSEMENT ) self.assertEqual(ecc.publicArea.type, TPM2_ALG.ECC) ecc_nv_nonce = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=0x1C0000B, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=15, ) ) eh = self.ectx.nv_define_space(b"", ecc_nv_nonce, ESYS_TR.OWNER) self.ectx.nv_write(eh, b"\xFF" * 15) nv_read = NVReadEK(self.ectx) _, ecc_nonce_template = create_ek_template("EK-ECC256", nv_read) _, ecc_nonce, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), ecc_nonce_template, ESYS_TR.ENDORSEMENT ) self.assertNotEqual( ecc_nonce.publicArea.unique.ecc.x, ecc.publicArea.unique.ecc.x ) self.assertNotEqual( ecc_nonce.publicArea.unique.ecc.y, ecc.publicArea.unique.ecc.y ) def test_create_ek_rsa(self): nv_read = NVReadEK(self.ectx) _, rsa_template = create_ek_template("EK-RSA2048", nv_read) _, rsa, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), rsa_template, ESYS_TR.ENDORSEMENT ) self.assertEqual(rsa.publicArea.type, TPM2_ALG.RSA) rsa_nv_nonce = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=0x1C00003, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=127, ) ) rh = self.ectx.nv_define_space(b"", rsa_nv_nonce, ESYS_TR.OWNER) self.ectx.nv_write(rh, b"\xFF" * 127) nv_read = NVReadEK(self.ectx) _, rsa_nonce_template = create_ek_template("EK-RSA2048", nv_read) _, rsa_nonce, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), rsa_nonce_template, ESYS_TR.ENDORSEMENT ) self.assertNotEqual(rsa_nonce.publicArea.unique.rsa, rsa.publicArea.unique.rsa) def test_create_ek_template(self): tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=0x1C0000C, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(tb), ) ) tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) self.ectx.nv_write(tnh, tb) nv_read = NVReadEK(self.ectx) _, templpub = create_ek_template("EK-ECC256", nv_read) _, templ, _, _, _ = self.ectx.create_primary( TPM2B_SENSITIVE_CREATE(), templpub, ESYS_TR.ENDORSEMENT ) self.assertEqual(templ.publicArea.type, TPM2_ALG.KEYEDHASH) def test_create_ek_bad(self): nv_read = NVReadEK(self.ectx) with self.assertRaises(ValueError) as e: create_ek_template("EK-DES", nv_read) self.assertEqual(str(e.exception), "unknown EK type EK-DES") def test_create_ek_high_rsa2048(self): nv_read = NVReadEK(self.ectx) with self.assertRaises(ValueError) as e: create_ek_template("EK-HIGH-RSA2048", nv_read) self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-RSA2048") template = ek_template.lookup("h-1") nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(b"I am a certificate"), ) ) cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) self.ectx.nv_write(cnh, b"I am a certificate") nv_read = NVReadEK(self.ectx) cert, key_template = create_ek_template("EK-HIGH-RSA2048", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(key_template.marshal(), template.template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index + 1, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(tb), ) ) tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) self.ectx.nv_write(tnh, tb) nv_read = NVReadEK(self.ectx) cert, template = create_ek_template("EK-HIGH-RSA2048", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual( template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() ) def test_create_ek_high_ecc256(self): nv_read = NVReadEK(self.ectx) with self.assertRaises(ValueError) as e: create_ek_template("EK-HIGH-ECC256", nv_read) self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-ECC256") template = ek_template.lookup("H-2") nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(b"I am a certificate"), ) ) cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) self.ectx.nv_write(cnh, b"I am a certificate") nv_read = NVReadEK(self.ectx) cert, key_template = create_ek_template("EK-HIGH-ECC256", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(key_template.marshal(), template.template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index + 1, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(tb), ) ) tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) self.ectx.nv_write(tnh, tb) nv_read = NVReadEK(self.ectx) cert, key_template = create_ek_template("EK-HIGH-ECC256", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual( key_template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() ) def test_create_ek_high_ecc384(self): nv_read = NVReadEK(self.ectx) with self.assertRaises(ValueError) as e: create_ek_template("EK-HIGH-ECC384", nv_read) self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-ECC384") template = ek_template.lookup("EK-HIGH-ECC384") nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(b"I am a certificate"), ) ) cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) self.ectx.nv_write(cnh, b"I am a certificate") nv_read = NVReadEK(self.ectx) cert, key_template = create_ek_template("EK-HIGH-ECC384", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(key_template.marshal(), template.template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=template.cert_index + 1, nameAlg=TPM2_ALG.SHA256, attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, dataSize=len(tb), ) ) tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) self.ectx.nv_write(tnh, tb) nv_read = NVReadEK(self.ectx) cert, key_template = create_ek_template("EK-HIGH-ECC384", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual( key_template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() ) def test_unmarshal_tools_pcr_values(self): b64val = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////////////////////////////" buf = b64decode(b64val) sels = TPML_PCR_SELECTION.parse("sha1:8,9+sha256:17") n, digs = unmarshal_tools_pcr_values(buf, sels) self.assertEqual(n, 72) self.assertEqual(digs[0], b"\x00" * 20) self.assertEqual(digs[1], b"\x00" * 20) self.assertEqual(digs[2], b"\xFF" * 32) def test_credential_to_tools(self): credential_blob = credential_to_tools(mkcred_id_object, mkcred_encrypted_secret) self.assertEqual(credential_blob, mkcred) def test_credential_to_tools_bytes(self): id_object = TPM2B_ID_OBJECT(mkcred_id_object) encrypted_secret = TPM2B_ENCRYPTED_SECRET(mkcred_encrypted_secret) credential_blob = credential_to_tools(id_object, encrypted_secret) self.assertEqual(credential_blob, mkcred) def test_tools_to_credential(self): id_object, encrypted_secret = tools_to_credential(mkcred) self.assertEqual(len(id_object), 45) self.assertEqual(len(encrypted_secret), 256) def test_tools_to_credential_invalid_magic(self): self.assertRaises( ValueError, lambda: tools_to_credential( int(0xBADCC0DF).to_bytes(4, "big") + int(1).to_bytes(4, "big") ), ) def test_tools_to_credential_invalid_version(self): self.assertRaises( ValueError, lambda: tools_to_credential( int(0xBADCC0DE).to_bytes(4, "big") + int(2).to_bytes(4, "big") ), ) if __name__ == "__main__": unittest.main()