pax_global_header00006660000000000000000000000064146372222050014515gustar00rootroot0000000000000052 comment=930cee2c45b84ac533c320b883b226edaeda9a38 tpm2-pytss-2.3.0/000077500000000000000000000000001463722220500135615ustar00rootroot00000000000000tpm2-pytss-2.3.0/.ci/000077500000000000000000000000001463722220500142325ustar00rootroot00000000000000tpm2-pytss-2.3.0/.ci/install-deps.sh000077500000000000000000000063671463722220500172040ustar00rootroot00000000000000#!/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"} export TPM2_TOOLS_VERSION=${TPM2_TOOLS_VERSION:-"5.5"} # # 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 # # 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/williamcroberts/ibmswtpm2.git -b fix-rc-exits pushd /tmp/ibmswtpm2/src make -j$(nproc) sudo cp tpm_server /usr/local/bin popd rm -fr /tmp/ibmswtpm2 fi # # Install tpm2-tools # if ! command -v tpm2; then # for git describe to work, one needs either a tag or a deep clone of master. if [ "${TPM2_TOOLS_VERSION}" != "master" ]; then tpm2_tools_extra_git_flags="--depth 1" fi git -C /tmp clone ${tpm2_tools_extra_git_flags} \ --branch "${TPM2_TOOLS_VERSION}" https://github.com/tpm2-software/tpm2-tools.git pushd /tmp/tpm2-tools ./bootstrap ./configure CFLAGS=-g --disable-fapi make -j$(nproc) sudo make install popd 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-2.3.0/.ci/run.sh000077500000000000000000000061411463722220500153770ustar00rootroot00000000000000#!/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}" } 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 fi tpm2-pytss-2.3.0/.coveragerc000066400000000000000000000003331463722220500157010ustar00rootroot00000000000000[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-2.3.0/.github/000077500000000000000000000000001463722220500151215ustar00rootroot00000000000000tpm2-pytss-2.3.0/.github/codeql.yml000066400000000000000000000000721463722220500171120ustar00rootroot00000000000000query-filters: - exclude: id: py/polluting-import tpm2-pytss-2.3.0/.github/dependabot.yml000066400000000000000000000007641463722220500177600ustar00rootroot00000000000000# 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-2.3.0/.github/workflows/000077500000000000000000000000001463722220500171565ustar00rootroot00000000000000tpm2-pytss-2.3.0/.github/workflows/codeql.yml000066400000000000000000000015611463722220500211530ustar00rootroot00000000000000name: "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-2.3.0/.github/workflows/publish_pkg.yaml000066400000000000000000000013671463722220500223600ustar00rootroot00000000000000name: 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-2.3.0/.github/workflows/tests.yaml000066400000000000000000000041731463722220500212110ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] tss-version: ['master', '2.4.0', '3.0.0', '3.0.3', '3.2.0', '4.0.0'] with-fapi: [true] tools-version: ['5.5'] include: - python-version: '3.9' tss-version: '3.1.0' 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-20.04 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.0.1 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@v3 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 --upgrade pip python3 -m pip install --user --upgrade black==19.10b0 - name: Check env: STYLE: 1 run: ./.ci/run.sh tpm2-pytss-2.3.0/.gitignore000066400000000000000000000007401463722220500155520ustar00rootroot00000000000000*.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-2.3.0/.gitmodules000066400000000000000000000000001463722220500157240ustar00rootroot00000000000000tpm2-pytss-2.3.0/.readthedocs.yml000066400000000000000000000004431463722220500166500ustar00rootroot00000000000000# 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-2.3.0/CHANGELOG.md000066400000000000000000000117311463722220500153750ustar00rootroot00000000000000# 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). ## 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-2.3.0/LICENSE000066400000000000000000000023241463722220500145670ustar00rootroot00000000000000Redistribution 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-2.3.0/MANIFEST.in000066400000000000000000000003631463722220500153210ustar00rootroot00000000000000include 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-2.3.0/README.md000066400000000000000000000045061463722220500150450ustar00rootroot00000000000000# 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-2.3.0/docs/000077500000000000000000000000001463722220500145115ustar00rootroot00000000000000tpm2-pytss-2.3.0/docs/CODE_OF_CONDUCT.md000066400000000000000000000125711463722220500173160ustar00rootroot00000000000000 # 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-2.3.0/docs/SECURITY.md000066400000000000000000000030361463722220500163040ustar00rootroot00000000000000# 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-2.3.0/docs/_static/000077500000000000000000000000001463722220500161375ustar00rootroot00000000000000tpm2-pytss-2.3.0/docs/_static/.gitkeep000066400000000000000000000000001463722220500175560ustar00rootroot00000000000000tpm2-pytss-2.3.0/docs/api.rst000066400000000000000000000006221463722220500160140ustar00rootroot00000000000000API ========== 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-2.3.0/docs/conf.py000066400000000000000000000122241463722220500160110ustar00rootroot00000000000000# 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-2.3.0/docs/constants.rst000066400000000000000000000002221463722220500172530ustar00rootroot00000000000000Constants ========= .. automodule:: tpm2_pytss.constants :members: :undoc-members: :inherited-members: int :special-members: __str__ tpm2-pytss-2.3.0/docs/contributing.rst000066400000000000000000000010621463722220500177510ustar00rootroot00000000000000Contributing ------------------- To contribute, please publish a PR and: - Keep within the existing style of black. The known working version is: ``19.10b0``. - `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``. - Sign off your commit with git option ``-s`` or ``--sign-off`` - Optionally, sign your commit with ``-S`` or ``--gpg-sign``. - Write a test. tpm2-pytss-2.3.0/docs/cryptography.rst000066400000000000000000000001431463722220500177740ustar00rootroot00000000000000cryptography ============ .. automodule:: tpm2_pytss.cryptography :members: :undoc-members: tpm2-pytss-2.3.0/docs/esys.rst000066400000000000000000000001131463722220500162210ustar00rootroot00000000000000Esys ==== .. autoclass:: tpm2_pytss.ESAPI :members: :undoc-members: tpm2-pytss-2.3.0/docs/exception.rst000066400000000000000000000001501463722220500172350ustar00rootroot00000000000000TSS2_Exception ============== .. autoclass:: tpm2_pytss.TSS2_Exception :members: :undoc-members: tpm2-pytss-2.3.0/docs/fapi.rst000066400000000000000000000001121463722220500161540ustar00rootroot00000000000000FAPI ==== .. autoclass:: tpm2_pytss.FAPI :members: :undoc-members: tpm2-pytss-2.3.0/docs/index.rst000066400000000000000000000035731463722220500163620ustar00rootroot00000000000000tpm2-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.8 - 3.9 - 3.10 - 3.11 - 3.12 .. toctree:: :hidden: :maxdepth: 2 :caption: Contents: install API Testing Project Info GitHub tpm2-pytss-2.3.0/docs/install.rst000066400000000000000000000066341463722220500167220ustar00rootroot00000000000000Installing ========== 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-2.3.0/docs/maintainers.rst000066400000000000000000000005401463722220500175540ustar00rootroot00000000000000.. _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-2.3.0/docs/policy.rst000066400000000000000000000001201463722220500165330ustar00rootroot00000000000000policy ====== .. autoclass:: tpm2_pytss.policy :members: :undoc-members: tpm2-pytss-2.3.0/docs/project.rst000066400000000000000000000005621463722220500167140ustar00rootroot00000000000000Project Information =================== Project details on release processes and contributing. .. toctree:: :maxdepth: 1 Release Process Contributing Maintainers Code of Conduct Security Practices LICENSE tpm2-pytss-2.3.0/docs/release.rst000066400000000000000000000102701463722220500166630ustar00rootroot00000000000000Release 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-2.3.0/docs/requirements.txt000066400000000000000000000003461463722220500200000ustar00rootroot00000000000000setuptools_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-2.3.0/docs/sphinx-finished.sh000077500000000000000000000012121463722220500201440ustar00rootroot00000000000000#!/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-2.3.0/docs/tcti.rst000066400000000000000000000003741463722220500162120ustar00rootroot00000000000000TCTI ==== .. 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-2.3.0/docs/testing.rst000066400000000000000000000005741463722220500167260ustar00rootroot00000000000000Testing ------- 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-2.3.0/docs/tsskey.rst000066400000000000000000000001341463722220500165630ustar00rootroot00000000000000tsskey ====== .. automodule:: tpm2_pytss.tsskey :members: TSSPrivKey :undoc-members: tpm2-pytss-2.3.0/docs/types.rst000066400000000000000000000002051463722220500164040ustar00rootroot00000000000000Types ===== .. automodule:: tpm2_pytss.types :members: :undoc-members: :inherited-members: int :special-members: __str__tpm2-pytss-2.3.0/docs/utils.rst000066400000000000000000000001211463722220500163750ustar00rootroot00000000000000utils ======== .. automodule:: tpm2_pytss.utils :members: :undoc-members: tpm2-pytss-2.3.0/pyproject.toml000066400000000000000000000007051463722220500164770ustar00rootroot00000000000000[build-system] requires = ["setuptools>=44", "wheel", "setuptools_scm[toml]>=3.4.3", "pycparser", "pkgconfig"] build-backend = "setuptools.build_meta" [tool.setuptools_scm] [tool.black] 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 ) ) ''' tpm2-pytss-2.3.0/scripts/000077500000000000000000000000001463722220500152505ustar00rootroot00000000000000tpm2-pytss-2.3.0/scripts/docs.sh000077500000000000000000000001361463722220500165370ustar00rootroot00000000000000#!/usr/bin/env sh # SPDX-License-Identifier: BSD-2 set -e sphinx-build -W -b html docs pages tpm2-pytss-2.3.0/scripts/get_deps.py000077500000000000000000000010671463722220500174230ustar00rootroot00000000000000#!/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-2.3.0/scripts/libtss2_build.py000066400000000000000000000062461463722220500203730ustar00rootroot00000000000000from 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-2.3.0/scripts/prepare_headers.py000066400000000000000000000306141463722220500207570ustar00rootroot00000000000000#!/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("#ifndef.*", "", s) s = re.sub("#if .*", "", s) s = re.sub("#define .*_H_*?\n", "", s) s = re.sub("#endif.*", "", s) s = re.sub("#error.*", "", s) s = re.sub('#ifdef __cplusplus\nextern "C" {', "", s, flags=re.MULTILINE) s = re.sub("#ifdef __cplusplus\n}", "", s, flags=re.MULTILINE) s = re.sub("#include.*", "", s) # Remove certain macros s = re.sub("#define TSS2_API_VERSION.*", "", s) s = re.sub("#define TSS2_ABI_VERSION.*", "", s) s = re.sub("#define TSS2_RC_LAYER\(level\).*", "", s) s = re.sub("(#define.*)TSS2_RC_LAYER\(0xff\)", "\g<1>0xff0000", s) # Remove comments s = re.sub("/\*.*?\*/", "", s, flags=re.MULTILINE) # Restructure #defines with ... s = re.sub("(#define [A-Za-z0-9_]+) +\(\(.*?\) \(.*?\)\)", "\g<1>...", s) s = re.sub("(#define [A-Za-z0-9_]+) +\(\(\(.*?\) .*\)", "\g<1>...", s) s = re.sub("(#define [A-Za-z0-9_]+) +\(\(.*?\).*?\) ", "\g<1>...", s) s = re.sub( "(#define [A-Za-z0-9_]+) .*\n.*?.*\)\)", "\g<1>...", s, flags=re.MULTILINE ) s = re.sub("(#define [A-Za-z0-9_]+) .*", "\g<1>...", s) # Restructure structs and untions with ... s = re.sub("\[.+?\]", "[...]", s) return s def remove_poll_stuff(s, poll_handle_type): r = r"#if defined\(__linux__\) \|\| defined\(__unix__\) \|\| defined\(__APPLE__\) \|\| defined \(__QNXNTO__\) \|\| defined \(__VXWORKS__\)(\n.*)+#endif\n#endif" s = re.sub(r, f"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", "", s) return re.sub(r"__attribute__\(\(deprecated\)\)", "", 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( "#define TPM2_MAX_TAGGED_POLICIES.*\n.*TPMS_TAGGED_POLICY\)\)", "", s, flags=re.MULTILINE, ) s = remove_INTERNALBUILD(s) s = re.sub( "typedef struct TPMS_ALGORITHM_DESCRIPTION TPMS_ALGORITHM_DESCRIPTION ;", "", s ) s = re.sub( r"struct TPMS_ALGORITHM_DESCRIPTION {\n.*\n.*\n} ;", "", 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("#ifndef TSS2_API_VERSION.*\n.*\n#endif", "", s, flags=re.MULTILINE) s = remove_poll_stuff(s, "TSS2_TCTI_POLL_HANDLE") s = re.sub(r"#define TSS2_TCTI_.*\n.*", "", s, flags=re.MULTILINE) s = re.sub(r"^\s*#define Tss2_Tcti_(?:.*\\\r?\n)*.*$", "", 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( "TSS2_RC\s+Tss2_MU_BYTE_Marshal\(.+?\);", s, re.DOTALL | re.MULTILINE ) if len(n) > 1: s = re.sub( "TSS2_RC\s+Tss2_MU_BYTE_Marshal\(.+?\);", "", s, 1, re.DOTALL | re.MULTILINE ) n = re.findall( "TSS2_RC\s+Tss2_MU_BYTE_Unmarshal\(.+?\);", s, re.DOTALL | re.MULTILINE ) if len(n) > 1: s = re.sub( "TSS2_RC\s+Tss2_MU_BYTE_Unmarshal\(.+?\);", "", s, 1, re.DOTALL | re.MULTILINE, ) s = re.sub( r"TSS2_RC\s+Tss2_MU_TPMS_ALGORITHM_DESCRIPTION_Marshal\(.+?\)\s+;", "", 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( "typedef enum TSS2_POLICY_PCR_SELECTOR TSS2_POLICY_PCR_SELECTOR;", "", 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-2.3.0/setup.cfg000066400000000000000000000023151463722220500154030ustar00rootroot00000000000000[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.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 [options] package_dir= =src packages= tpm2_pytss tpm2_pytss.internal setup_requires = setuptools_scm[toml]>=3.4.3 cffi>=1.0.0 pkgconfig cryptography>=3.0 asn1crypto packaging pycparser install_requires = cffi>=1.0.0 asn1crypto cryptography>=3.0 packaging pyyaml [options.extras_require] dev = docutils==0.16 coverage sphinx sphinx-rtd-theme twine setuptools_scm[toml]>=3.4.3 black==19.10b0 pytest pytest-xdist pytest-cov myst-parser build installer tpm2-pytss-2.3.0/setup.py000066400000000000000000000216211463722220500152750ustar00rootroot00000000000000import site import sys import os 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:] 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", "TPM2_HANDLE", "TPM2_GENERATED", "ESYS_TR", "TSS2_POLICY_PCR_SELECTOR", ) ) 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']}" ) pdata = preprocess_file( header_path, cpp_args=["-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: pdata = preprocess_file( policy_header_path, cpp_args=[ "-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' estr = "" for k, v in element_type_map.items(): estr = estr + f' "{k}": "{v}",\n' versions = self.get_versions() vstr = "" for k, v in versions.items(): vstr = vstr + f' "{k}": "{v}",\n' 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) vtempl = dedent(self.version_template) vout = vtempl.format(vstr=vstr) 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-2.3.0/src/000077500000000000000000000000001463722220500143505ustar00rootroot00000000000000tpm2-pytss-2.3.0/src/tpm2_pytss/000077500000000000000000000000001463722220500164745ustar00rootroot00000000000000tpm2-pytss-2.3.0/src/tpm2_pytss/ESAPI.py000066400000000000000000010606401463722220500177160ustar00rootroot00000000000000# 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 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], 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): The algorithm and key size for parameter encryption. Can use strings understood by TPMT_SYM_DEF.parse(). 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) 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]) 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_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]) 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]) 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]), 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]) 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]) 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]) 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 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: TPMT_TK_HASHCHECK, 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): Proof that digest was created by the TPM. 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") 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, nonce_tpm: Union[TPM2B_NONCE, bytes, str], cp_hash_a: Union[TPM2B_DIGEST, bytes, str], policy_ref: Union[TPM2B_NONCE, bytes, str], expiration: int, auth: TPMT_SIGNATURE, 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. nonce_tpm (Union[TPM2B_NONCE, bytes, str]): The policy nonce for the session. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer. expiration (int): Time when authorization will expire, measured in seconds from the time that nonceTPM was generated. auth (TPMT_SIGNATURE): Signed authorization (not optional). 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], cp_hash_a: Union[TPM2B_DIGEST, bytes, str], policy_ref: Union[TPM2B_NONCE, bytes, str], expiration: int, 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. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer. expiration (int): Time when authorization will expire, measured in seconds from the time that nonceTPM was generated. 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, cp_hash_a: Union[TPM2B_DIGEST, bytes, str], policy_ref: Union[TPM2B_NONCE, bytes, str], auth_name: Union[TPM2B_NAME, bytes, str], ticket: TPMT_TK_AUTH, 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. cp_hash_a (Union[TPM2B_DIGEST, bytes, str]): Digest of the command parameters to which this authorization is limited. policy_ref (Union[TPM2B_NONCE, bytes, str]): policyRef A reference to a policy relating to the authorization - may be the Empty Buffer. 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(). 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], 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]): Expected digest value of the selected PCR using the hash algorithm of the session; may be zero length. 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") 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], policy_ref: Union[TPM2B_NONCE, bytes, str], key_sign: Union[TPM2B_NAME, bytes, str], check_ticket: TPMT_TK_VERIFIED, 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. policy_ref (Union[TPM2B_NONCE, bytes, str]): A policy qualifier. 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. 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]), 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]) 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 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]) 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]) @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-2.3.0/src/tpm2_pytss/FAPI.py000066400000000000000000001456721463722220500176040ustar00rootroot00000000000000# 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) 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. 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-2.3.0/src/tpm2_pytss/TCTI.py000066400000000000000000000474211463722220500176210ustar00rootroot00000000000000# 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-2.3.0/src/tpm2_pytss/TCTILdr.py000066400000000000000000000044741463722220500202640ustar00rootroot00000000000000# 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-2.3.0/src/tpm2_pytss/TCTISPIHelper.py000066400000000000000000000230521463722220500213270ustar00rootroot00000000000000# 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-2.3.0/src/tpm2_pytss/TSS2_Exception.py000066400000000000000000000040511463722220500216170ustar00rootroot00000000000000from ._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-2.3.0/src/tpm2_pytss/__init__.py000066400000000000000000000016611463722220500206110ustar00rootroot00000000000000import _cffi_backend # check that we can load the C bindings, # if we can't, provide a better message. try: from ._libtpm2_pytss import lib 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 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 from .types import * from .constants import * from .TSS2_Exception import TSS2_Exception tpm2-pytss-2.3.0/src/tpm2_pytss/constants.py000066400000000000000000001634721463722220500210770ustar00rootroot00000000000000# 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, _lib_version_atleast, _chkrc, ) class TPM_FRIENDLY_INT(int): _FIXUP_MAP = {} @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 iterator(cls) -> filter: """ Returns the constants in the class. Returns: (int): The int values of the constants in the class. Example: list(ESYS_TR.iterator()) -> [4095, 255, 0, 1, 2, 3, ... ] """ return filter(lambda x: isinstance(x, int), vars(cls).values()) @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: ESYS_TR.contains(7) -> True """ return value in cls.iterator() @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)) @staticmethod def _copy_and_set(dstcls, srccls): """Copy class variables from srccls to dstcls srccls must be a subclass on TPM_FRIENDLY_INT. Sets the the variable type to dstcls when copying. dstcls and srccls can be the same. Skip setting destination if the dstcls variable already have the correct type. """ if not issubclass(srccls, TPM_FRIENDLY_INT): return for k, v in vars(srccls).items(): dv = getattr(dstcls, k, None) if not isinstance(v, int) or k.startswith("_") or type(dv) == type(dstcls): continue fv = dstcls(v) setattr(dstcls, k, fv) @staticmethod def _fix_const_type(cls): """Ensure constants in a TPM2 constant class have the correct type We also copy constants from a superclass in case it's of the correct type. """ for sc in cls.__mro__: if sc in (TPM_FRIENDLY_INT, TPMA_FRIENDLY_INTLIST): break TPM_FRIENDLY_INT._copy_and_set(cls, sc) return cls 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 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) @TPM_FRIENDLY_INT._fix_const_type 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` """ NONE = lib.ESYS_TR_NONE PASSWORD = lib.ESYS_TR_PASSWORD PCR0 = lib.ESYS_TR_PCR0 PCR1 = lib.ESYS_TR_PCR1 PCR2 = lib.ESYS_TR_PCR2 PCR3 = lib.ESYS_TR_PCR3 PCR4 = lib.ESYS_TR_PCR4 PCR5 = lib.ESYS_TR_PCR5 PCR6 = lib.ESYS_TR_PCR6 PCR7 = lib.ESYS_TR_PCR7 PCR8 = lib.ESYS_TR_PCR8 PCR9 = lib.ESYS_TR_PCR9 PCR10 = lib.ESYS_TR_PCR10 PCR11 = lib.ESYS_TR_PCR11 PCR12 = lib.ESYS_TR_PCR12 PCR13 = lib.ESYS_TR_PCR13 PCR14 = lib.ESYS_TR_PCR14 PCR15 = lib.ESYS_TR_PCR15 PCR16 = lib.ESYS_TR_PCR16 PCR17 = lib.ESYS_TR_PCR17 PCR18 = lib.ESYS_TR_PCR18 PCR19 = lib.ESYS_TR_PCR19 PCR20 = lib.ESYS_TR_PCR20 PCR21 = lib.ESYS_TR_PCR21 PCR22 = lib.ESYS_TR_PCR22 PCR23 = lib.ESYS_TR_PCR23 PCR24 = lib.ESYS_TR_PCR24 PCR25 = lib.ESYS_TR_PCR25 PCR26 = lib.ESYS_TR_PCR26 PCR27 = lib.ESYS_TR_PCR27 PCR28 = lib.ESYS_TR_PCR28 PCR29 = lib.ESYS_TR_PCR29 PCR30 = lib.ESYS_TR_PCR30 PCR31 = lib.ESYS_TR_PCR31 OWNER = lib.ESYS_TR_RH_OWNER NULL = lib.ESYS_TR_RH_NULL LOCKOUT = lib.ESYS_TR_RH_LOCKOUT ENDORSEMENT = lib.ESYS_TR_RH_ENDORSEMENT PLATFORM = lib.ESYS_TR_RH_PLATFORM PLATFORM_NV = lib.ESYS_TR_RH_PLATFORM_NV RH_OWNER = lib.ESYS_TR_RH_OWNER RH_NULL = lib.ESYS_TR_RH_NULL RH_LOCKOUT = lib.ESYS_TR_RH_LOCKOUT RH_ENDORSEMENT = lib.ESYS_TR_RH_ENDORSEMENT RH_PLATFORM = lib.ESYS_TR_RH_PLATFORM RH_PLATFORM_NV = lib.ESYS_TR_RH_PLATFORM_NV 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) @TPM_FRIENDLY_INT._fix_const_type class TPM2_RH(TPM_FRIENDLY_INT): SRK = lib.TPM2_RH_SRK OWNER = lib.TPM2_RH_OWNER REVOKE = lib.TPM2_RH_REVOKE TRANSPORT = lib.TPM2_RH_TRANSPORT OPERATOR = lib.TPM2_RH_OPERATOR ADMIN = lib.TPM2_RH_ADMIN EK = lib.TPM2_RH_EK NULL = lib.TPM2_RH_NULL UNASSIGNED = lib.TPM2_RH_UNASSIGNED try: PW = lib.TPM2_RS_PW except AttributeError: PW = lib.TPM2_RH_PW LOCKOUT = lib.TPM2_RH_LOCKOUT ENDORSEMENT = lib.TPM2_RH_ENDORSEMENT PLATFORM = lib.TPM2_RH_PLATFORM PLATFORM_NV = lib.TPM2_RH_PLATFORM_NV @TPM_FRIENDLY_INT._fix_const_type class TPM2_ALG(TPM_FRIENDLY_INT): _alias_name = "TPM2_ALG_ID" ERROR = lib.TPM2_ALG_ERROR RSA = lib.TPM2_ALG_RSA TDES = lib.TPM2_ALG_TDES SHA = lib.TPM2_ALG_SHA SHA1 = lib.TPM2_ALG_SHA1 HMAC = lib.TPM2_ALG_HMAC AES = lib.TPM2_ALG_AES MGF1 = lib.TPM2_ALG_MGF1 KEYEDHASH = lib.TPM2_ALG_KEYEDHASH XOR = lib.TPM2_ALG_XOR SHA256 = lib.TPM2_ALG_SHA256 SHA384 = lib.TPM2_ALG_SHA384 SHA512 = lib.TPM2_ALG_SHA512 NULL = lib.TPM2_ALG_NULL SM3_256 = lib.TPM2_ALG_SM3_256 SM4 = lib.TPM2_ALG_SM4 RSASSA = lib.TPM2_ALG_RSASSA RSAES = lib.TPM2_ALG_RSAES RSAPSS = lib.TPM2_ALG_RSAPSS OAEP = lib.TPM2_ALG_OAEP ECDSA = lib.TPM2_ALG_ECDSA ECDH = lib.TPM2_ALG_ECDH ECDAA = lib.TPM2_ALG_ECDAA SM2 = lib.TPM2_ALG_SM2 ECSCHNORR = lib.TPM2_ALG_ECSCHNORR ECMQV = lib.TPM2_ALG_ECMQV KDF1_SP800_56A = lib.TPM2_ALG_KDF1_SP800_56A KDF2 = lib.TPM2_ALG_KDF2 KDF1_SP800_108 = lib.TPM2_ALG_KDF1_SP800_108 ECC = lib.TPM2_ALG_ECC SYMCIPHER = lib.TPM2_ALG_SYMCIPHER CAMELLIA = lib.TPM2_ALG_CAMELLIA CTR = lib.TPM2_ALG_CTR SHA3_256 = lib.TPM2_ALG_SHA3_256 SHA3_384 = lib.TPM2_ALG_SHA3_384 SHA3_512 = lib.TPM2_ALG_SHA3_512 OFB = lib.TPM2_ALG_OFB CBC = lib.TPM2_ALG_CBC CFB = lib.TPM2_ALG_CFB ECB = lib.TPM2_ALG_ECB FIRST = lib.TPM2_ALG_FIRST LAST = lib.TPM2_ALG_LAST @TPM_FRIENDLY_INT._fix_const_type class TPM2_ALG_ID(TPM2_ALG): pass @TPM_FRIENDLY_INT._fix_const_type class TPM2_ECC(TPM_FRIENDLY_INT): NONE = lib.TPM2_ECC_NONE NIST_P192 = lib.TPM2_ECC_NIST_P192 NIST_P224 = lib.TPM2_ECC_NIST_P224 NIST_P256 = lib.TPM2_ECC_NIST_P256 NIST_P384 = lib.TPM2_ECC_NIST_P384 NIST_P521 = lib.TPM2_ECC_NIST_P521 BN_P256 = lib.TPM2_ECC_BN_P256 BN_P638 = lib.TPM2_ECC_BN_P638 SM2_P256 = lib.TPM2_ECC_SM2_P256 _FIXUP_MAP = { "192": "NIST_P192", "224": "NIST_P224", "256": "NIST_P256", "384": "NIST_P384", "521": "NIST_P521", "SM2": "SM2_P256", } @TPM_FRIENDLY_INT._fix_const_type class TPM2_ECC_CURVE(TPM2_ECC): pass @TPM_FRIENDLY_INT._fix_const_type class TPM2_CC(TPM_FRIENDLY_INT): NV_UndefineSpaceSpecial = lib.TPM2_CC_NV_UndefineSpaceSpecial FIRST = lib.TPM2_CC_FIRST EvictControl = lib.TPM2_CC_EvictControl HierarchyControl = lib.TPM2_CC_HierarchyControl NV_UndefineSpace = lib.TPM2_CC_NV_UndefineSpace ChangeEPS = lib.TPM2_CC_ChangeEPS ChangePPS = lib.TPM2_CC_ChangePPS Clear = lib.TPM2_CC_Clear ClearControl = lib.TPM2_CC_ClearControl ClockSet = lib.TPM2_CC_ClockSet HierarchyChangeAuth = lib.TPM2_CC_HierarchyChangeAuth NV_DefineSpace = lib.TPM2_CC_NV_DefineSpace PCR_Allocate = lib.TPM2_CC_PCR_Allocate PCR_SetAuthPolicy = lib.TPM2_CC_PCR_SetAuthPolicy PP_Commands = lib.TPM2_CC_PP_Commands SetPrimaryPolicy = lib.TPM2_CC_SetPrimaryPolicy FieldUpgradeStart = lib.TPM2_CC_FieldUpgradeStart ClockRateAdjust = lib.TPM2_CC_ClockRateAdjust CreatePrimary = lib.TPM2_CC_CreatePrimary NV_GlobalWriteLock = lib.TPM2_CC_NV_GlobalWriteLock GetCommandAuditDigest = lib.TPM2_CC_GetCommandAuditDigest NV_Increment = lib.TPM2_CC_NV_Increment NV_SetBits = lib.TPM2_CC_NV_SetBits NV_Extend = lib.TPM2_CC_NV_Extend NV_Write = lib.TPM2_CC_NV_Write NV_WriteLock = lib.TPM2_CC_NV_WriteLock DictionaryAttackLockReset = lib.TPM2_CC_DictionaryAttackLockReset DictionaryAttackParameters = lib.TPM2_CC_DictionaryAttackParameters NV_ChangeAuth = lib.TPM2_CC_NV_ChangeAuth PCR_Event = lib.TPM2_CC_PCR_Event PCR_Reset = lib.TPM2_CC_PCR_Reset SequenceComplete = lib.TPM2_CC_SequenceComplete SetAlgorithmSet = lib.TPM2_CC_SetAlgorithmSet SetCommandCodeAuditStatus = lib.TPM2_CC_SetCommandCodeAuditStatus FieldUpgradeData = lib.TPM2_CC_FieldUpgradeData IncrementalSelfTest = lib.TPM2_CC_IncrementalSelfTest SelfTest = lib.TPM2_CC_SelfTest Startup = lib.TPM2_CC_Startup Shutdown = lib.TPM2_CC_Shutdown StirRandom = lib.TPM2_CC_StirRandom ActivateCredential = lib.TPM2_CC_ActivateCredential Certify = lib.TPM2_CC_Certify PolicyNV = lib.TPM2_CC_PolicyNV CertifyCreation = lib.TPM2_CC_CertifyCreation Duplicate = lib.TPM2_CC_Duplicate GetTime = lib.TPM2_CC_GetTime GetSessionAuditDigest = lib.TPM2_CC_GetSessionAuditDigest NV_Read = lib.TPM2_CC_NV_Read NV_ReadLock = lib.TPM2_CC_NV_ReadLock ObjectChangeAuth = lib.TPM2_CC_ObjectChangeAuth PolicySecret = lib.TPM2_CC_PolicySecret Rewrap = lib.TPM2_CC_Rewrap Create = lib.TPM2_CC_Create ECDH_ZGen = lib.TPM2_CC_ECDH_ZGen HMAC = lib.TPM2_CC_HMAC Import = lib.TPM2_CC_Import Load = lib.TPM2_CC_Load Quote = lib.TPM2_CC_Quote RSA_Decrypt = lib.TPM2_CC_RSA_Decrypt HMAC_Start = lib.TPM2_CC_HMAC_Start SequenceUpdate = lib.TPM2_CC_SequenceUpdate Sign = lib.TPM2_CC_Sign Unseal = lib.TPM2_CC_Unseal PolicySigned = lib.TPM2_CC_PolicySigned ContextLoad = lib.TPM2_CC_ContextLoad ContextSave = lib.TPM2_CC_ContextSave ECDH_KeyGen = lib.TPM2_CC_ECDH_KeyGen EncryptDecrypt = lib.TPM2_CC_EncryptDecrypt FlushContext = lib.TPM2_CC_FlushContext LoadExternal = lib.TPM2_CC_LoadExternal MakeCredential = lib.TPM2_CC_MakeCredential NV_ReadPublic = lib.TPM2_CC_NV_ReadPublic PolicyAuthorize = lib.TPM2_CC_PolicyAuthorize PolicyAuthValue = lib.TPM2_CC_PolicyAuthValue PolicyCommandCode = lib.TPM2_CC_PolicyCommandCode PolicyCounterTimer = lib.TPM2_CC_PolicyCounterTimer PolicyCpHash = lib.TPM2_CC_PolicyCpHash PolicyLocality = lib.TPM2_CC_PolicyLocality PolicyNameHash = lib.TPM2_CC_PolicyNameHash PolicyOR = lib.TPM2_CC_PolicyOR PolicyTicket = lib.TPM2_CC_PolicyTicket ReadPublic = lib.TPM2_CC_ReadPublic RSA_Encrypt = lib.TPM2_CC_RSA_Encrypt StartAuthSession = lib.TPM2_CC_StartAuthSession VerifySignature = lib.TPM2_CC_VerifySignature ECC_Parameters = lib.TPM2_CC_ECC_Parameters FirmwareRead = lib.TPM2_CC_FirmwareRead GetCapability = lib.TPM2_CC_GetCapability GetRandom = lib.TPM2_CC_GetRandom GetTestResult = lib.TPM2_CC_GetTestResult Hash = lib.TPM2_CC_Hash PCR_Read = lib.TPM2_CC_PCR_Read PolicyPCR = lib.TPM2_CC_PolicyPCR PolicyRestart = lib.TPM2_CC_PolicyRestart ReadClock = lib.TPM2_CC_ReadClock PCR_Extend = lib.TPM2_CC_PCR_Extend PCR_SetAuthValue = lib.TPM2_CC_PCR_SetAuthValue NV_Certify = lib.TPM2_CC_NV_Certify EventSequenceComplete = lib.TPM2_CC_EventSequenceComplete HashSequenceStart = lib.TPM2_CC_HashSequenceStart PolicyPhysicalPresence = lib.TPM2_CC_PolicyPhysicalPresence PolicyDuplicationSelect = lib.TPM2_CC_PolicyDuplicationSelect PolicyGetDigest = lib.TPM2_CC_PolicyGetDigest TestParms = lib.TPM2_CC_TestParms Commit = lib.TPM2_CC_Commit PolicyPassword = lib.TPM2_CC_PolicyPassword ZGen_2Phase = lib.TPM2_CC_ZGen_2Phase EC_Ephemeral = lib.TPM2_CC_EC_Ephemeral PolicyNvWritten = lib.TPM2_CC_PolicyNvWritten PolicyTemplate = lib.TPM2_CC_PolicyTemplate CreateLoaded = lib.TPM2_CC_CreateLoaded PolicyAuthorizeNV = lib.TPM2_CC_PolicyAuthorizeNV EncryptDecrypt2 = lib.TPM2_CC_EncryptDecrypt2 AC_GetCapability = lib.TPM2_CC_AC_GetCapability AC_Send = lib.TPM2_CC_AC_Send Policy_AC_SendSelect = lib.TPM2_CC_Policy_AC_SendSelect LAST = lib.TPM2_CC_LAST Vendor_TCG_Test = lib.TPM2_CC_Vendor_TCG_Test @TPM_FRIENDLY_INT._fix_const_type class TPM2_SPEC(TPM_FRIENDLY_INT): FAMILY = lib.TPM2_SPEC_FAMILY LEVEL = lib.TPM2_SPEC_LEVEL VERSION = lib.TPM2_SPEC_VERSION YEAR = lib.TPM2_SPEC_YEAR DAY_OF_YEAR = lib.TPM2_SPEC_DAY_OF_YEAR @TPM_FRIENDLY_INT._fix_const_type class TPM2_GENERATED(TPM_FRIENDLY_INT): VALUE = lib.TPM2_GENERATED_VALUE class TPM_BASE_RC(TPM_FRIENDLY_INT): def decode(self): return ffi.string(lib.Tss2_RC_Decode(self)).decode() @TPM_FRIENDLY_INT._fix_const_type class TPM2_RC(TPM_BASE_RC): SUCCESS = lib.TPM2_RC_SUCCESS BAD_TAG = lib.TPM2_RC_BAD_TAG VER1 = lib.TPM2_RC_VER1 INITIALIZE = lib.TPM2_RC_INITIALIZE FAILURE = lib.TPM2_RC_FAILURE SEQUENCE = lib.TPM2_RC_SEQUENCE PRIVATE = lib.TPM2_RC_PRIVATE HMAC = lib.TPM2_RC_HMAC DISABLED = lib.TPM2_RC_DISABLED EXCLUSIVE = lib.TPM2_RC_EXCLUSIVE AUTH_TYPE = lib.TPM2_RC_AUTH_TYPE AUTH_MISSING = lib.TPM2_RC_AUTH_MISSING POLICY = lib.TPM2_RC_POLICY PCR = lib.TPM2_RC_PCR PCR_CHANGED = lib.TPM2_RC_PCR_CHANGED UPGRADE = lib.TPM2_RC_UPGRADE TOO_MANY_CONTEXTS = lib.TPM2_RC_TOO_MANY_CONTEXTS AUTH_UNAVAILABLE = lib.TPM2_RC_AUTH_UNAVAILABLE REBOOT = lib.TPM2_RC_REBOOT UNBALANCED = lib.TPM2_RC_UNBALANCED COMMAND_SIZE = lib.TPM2_RC_COMMAND_SIZE COMMAND_CODE = lib.TPM2_RC_COMMAND_CODE AUTHSIZE = lib.TPM2_RC_AUTHSIZE AUTH_CONTEXT = lib.TPM2_RC_AUTH_CONTEXT NV_RANGE = lib.TPM2_RC_NV_RANGE NV_SIZE = lib.TPM2_RC_NV_SIZE NV_LOCKED = lib.TPM2_RC_NV_LOCKED NV_AUTHORIZATION = lib.TPM2_RC_NV_AUTHORIZATION NV_UNINITIALIZED = lib.TPM2_RC_NV_UNINITIALIZED NV_SPACE = lib.TPM2_RC_NV_SPACE NV_DEFINED = lib.TPM2_RC_NV_DEFINED BAD_CONTEXT = lib.TPM2_RC_BAD_CONTEXT CPHASH = lib.TPM2_RC_CPHASH PARENT = lib.TPM2_RC_PARENT NEEDS_TEST = lib.TPM2_RC_NEEDS_TEST NO_RESULT = lib.TPM2_RC_NO_RESULT SENSITIVE = lib.TPM2_RC_SENSITIVE MAX_FM0 = lib.TPM2_RC_MAX_FM0 FMT1 = lib.TPM2_RC_FMT1 ASYMMETRIC = lib.TPM2_RC_ASYMMETRIC ATTRIBUTES = lib.TPM2_RC_ATTRIBUTES HASH = lib.TPM2_RC_HASH VALUE = lib.TPM2_RC_VALUE HIERARCHY = lib.TPM2_RC_HIERARCHY KEY_SIZE = lib.TPM2_RC_KEY_SIZE MGF = lib.TPM2_RC_MGF MODE = lib.TPM2_RC_MODE TYPE = lib.TPM2_RC_TYPE HANDLE = lib.TPM2_RC_HANDLE KDF = lib.TPM2_RC_KDF RANGE = lib.TPM2_RC_RANGE AUTH_FAIL = lib.TPM2_RC_AUTH_FAIL NONCE = lib.TPM2_RC_NONCE PP = lib.TPM2_RC_PP SCHEME = lib.TPM2_RC_SCHEME SIZE = lib.TPM2_RC_SIZE SYMMETRIC = lib.TPM2_RC_SYMMETRIC TAG = lib.TPM2_RC_TAG SELECTOR = lib.TPM2_RC_SELECTOR INSUFFICIENT = lib.TPM2_RC_INSUFFICIENT SIGNATURE = lib.TPM2_RC_SIGNATURE KEY = lib.TPM2_RC_KEY POLICY_FAIL = lib.TPM2_RC_POLICY_FAIL INTEGRITY = lib.TPM2_RC_INTEGRITY TICKET = lib.TPM2_RC_TICKET BAD_AUTH = lib.TPM2_RC_BAD_AUTH EXPIRED = lib.TPM2_RC_EXPIRED POLICY_CC = lib.TPM2_RC_POLICY_CC BINDING = lib.TPM2_RC_BINDING CURVE = lib.TPM2_RC_CURVE ECC_POINT = lib.TPM2_RC_ECC_POINT WARN = lib.TPM2_RC_WARN CONTEXT_GAP = lib.TPM2_RC_CONTEXT_GAP OBJECT_MEMORY = lib.TPM2_RC_OBJECT_MEMORY SESSION_MEMORY = lib.TPM2_RC_SESSION_MEMORY MEMORY = lib.TPM2_RC_MEMORY SESSION_HANDLES = lib.TPM2_RC_SESSION_HANDLES OBJECT_HANDLES = lib.TPM2_RC_OBJECT_HANDLES LOCALITY = lib.TPM2_RC_LOCALITY YIELDED = lib.TPM2_RC_YIELDED CANCELED = lib.TPM2_RC_CANCELED TESTING = lib.TPM2_RC_TESTING REFERENCE_H0 = lib.TPM2_RC_REFERENCE_H0 REFERENCE_H1 = lib.TPM2_RC_REFERENCE_H1 REFERENCE_H2 = lib.TPM2_RC_REFERENCE_H2 REFERENCE_H3 = lib.TPM2_RC_REFERENCE_H3 REFERENCE_H4 = lib.TPM2_RC_REFERENCE_H4 REFERENCE_H5 = lib.TPM2_RC_REFERENCE_H5 REFERENCE_H6 = lib.TPM2_RC_REFERENCE_H6 REFERENCE_S0 = lib.TPM2_RC_REFERENCE_S0 REFERENCE_S1 = lib.TPM2_RC_REFERENCE_S1 REFERENCE_S2 = lib.TPM2_RC_REFERENCE_S2 REFERENCE_S3 = lib.TPM2_RC_REFERENCE_S3 REFERENCE_S4 = lib.TPM2_RC_REFERENCE_S4 REFERENCE_S5 = lib.TPM2_RC_REFERENCE_S5 REFERENCE_S6 = lib.TPM2_RC_REFERENCE_S6 NV_RATE = lib.TPM2_RC_NV_RATE LOCKOUT = lib.TPM2_RC_LOCKOUT RETRY = lib.TPM2_RC_RETRY NV_UNAVAILABLE = lib.TPM2_RC_NV_UNAVAILABLE NOT_USED = lib.TPM2_RC_NOT_USED H = lib.TPM2_RC_H P = lib.TPM2_RC_P S = lib.TPM2_RC_S RC1 = lib.TPM2_RC_1 RC2 = lib.TPM2_RC_2 RC3 = lib.TPM2_RC_3 RC4 = lib.TPM2_RC_4 RC5 = lib.TPM2_RC_5 RC6 = lib.TPM2_RC_6 RC7 = lib.TPM2_RC_7 RC8 = lib.TPM2_RC_8 RC9 = lib.TPM2_RC_9 A = lib.TPM2_RC_A B = lib.TPM2_RC_B C = lib.TPM2_RC_C D = lib.TPM2_RC_D E = lib.TPM2_RC_E F = lib.TPM2_RC_F N_MASK = lib.TPM2_RC_N_MASK @TPM_FRIENDLY_INT._fix_const_type class TSS2_RC(TPM_BASE_RC): RC_LAYER_SHIFT = lib.TSS2_RC_LAYER_SHIFT RC_LAYER_MASK = lib.TSS2_RC_LAYER_MASK TPM_RC_LAYER = lib.TSS2_TPM_RC_LAYER FEATURE_RC_LAYER = lib.TSS2_FEATURE_RC_LAYER ESAPI_RC_LAYER = lib.TSS2_ESAPI_RC_LAYER SYS_RC_LAYER = lib.TSS2_SYS_RC_LAYER MU_RC_LAYER = lib.TSS2_MU_RC_LAYER TCTI_RC_LAYER = lib.TSS2_TCTI_RC_LAYER RESMGR_RC_LAYER = lib.TSS2_RESMGR_RC_LAYER RESMGR_TPM_RC_LAYER = lib.TSS2_RESMGR_TPM_RC_LAYER BASE_RC_GENERAL_FAILURE = lib.TSS2_BASE_RC_GENERAL_FAILURE BASE_RC_NOT_IMPLEMENTED = lib.TSS2_BASE_RC_NOT_IMPLEMENTED BASE_RC_BAD_CONTEXT = lib.TSS2_BASE_RC_BAD_CONTEXT BASE_RC_ABI_MISMATCH = lib.TSS2_BASE_RC_ABI_MISMATCH BASE_RC_BAD_REFERENCE = lib.TSS2_BASE_RC_BAD_REFERENCE BASE_RC_INSUFFICIENT_BUFFER = lib.TSS2_BASE_RC_INSUFFICIENT_BUFFER BASE_RC_BAD_SEQUENCE = lib.TSS2_BASE_RC_BAD_SEQUENCE BASE_RC_NO_CONNECTION = lib.TSS2_BASE_RC_NO_CONNECTION BASE_RC_TRY_AGAIN = lib.TSS2_BASE_RC_TRY_AGAIN BASE_RC_IO_ERROR = lib.TSS2_BASE_RC_IO_ERROR BASE_RC_BAD_VALUE = lib.TSS2_BASE_RC_BAD_VALUE BASE_RC_NOT_PERMITTED = lib.TSS2_BASE_RC_NOT_PERMITTED BASE_RC_INVALID_SESSIONS = lib.TSS2_BASE_RC_INVALID_SESSIONS BASE_RC_NO_DECRYPT_PARAM = lib.TSS2_BASE_RC_NO_DECRYPT_PARAM BASE_RC_NO_ENCRYPT_PARAM = lib.TSS2_BASE_RC_NO_ENCRYPT_PARAM BASE_RC_BAD_SIZE = lib.TSS2_BASE_RC_BAD_SIZE BASE_RC_MALFORMED_RESPONSE = lib.TSS2_BASE_RC_MALFORMED_RESPONSE BASE_RC_INSUFFICIENT_CONTEXT = lib.TSS2_BASE_RC_INSUFFICIENT_CONTEXT BASE_RC_INSUFFICIENT_RESPONSE = lib.TSS2_BASE_RC_INSUFFICIENT_RESPONSE BASE_RC_INCOMPATIBLE_TCTI = lib.TSS2_BASE_RC_INCOMPATIBLE_TCTI BASE_RC_NOT_SUPPORTED = lib.TSS2_BASE_RC_NOT_SUPPORTED BASE_RC_BAD_TCTI_STRUCTURE = lib.TSS2_BASE_RC_BAD_TCTI_STRUCTURE BASE_RC_MEMORY = lib.TSS2_BASE_RC_MEMORY BASE_RC_BAD_TR = lib.TSS2_BASE_RC_BAD_TR BASE_RC_MULTIPLE_DECRYPT_SESSIONS = lib.TSS2_BASE_RC_MULTIPLE_DECRYPT_SESSIONS BASE_RC_MULTIPLE_ENCRYPT_SESSIONS = lib.TSS2_BASE_RC_MULTIPLE_ENCRYPT_SESSIONS BASE_RC_RSP_AUTH_FAILED = lib.TSS2_BASE_RC_RSP_AUTH_FAILED BASE_RC_NO_CONFIG = lib.TSS2_BASE_RC_NO_CONFIG BASE_RC_BAD_PATH = lib.TSS2_BASE_RC_BAD_PATH BASE_RC_NOT_DELETABLE = lib.TSS2_BASE_RC_NOT_DELETABLE BASE_RC_PATH_ALREADY_EXISTS = lib.TSS2_BASE_RC_PATH_ALREADY_EXISTS BASE_RC_KEY_NOT_FOUND = lib.TSS2_BASE_RC_KEY_NOT_FOUND BASE_RC_SIGNATURE_VERIFICATION_FAILED = ( lib.TSS2_BASE_RC_SIGNATURE_VERIFICATION_FAILED ) BASE_RC_HASH_MISMATCH = lib.TSS2_BASE_RC_HASH_MISMATCH BASE_RC_KEY_NOT_DUPLICABLE = lib.TSS2_BASE_RC_KEY_NOT_DUPLICABLE BASE_RC_PATH_NOT_FOUND = lib.TSS2_BASE_RC_PATH_NOT_FOUND BASE_RC_NO_CERT = lib.TSS2_BASE_RC_NO_CERT BASE_RC_NO_PCR = lib.TSS2_BASE_RC_NO_PCR BASE_RC_PCR_NOT_RESETTABLE = lib.TSS2_BASE_RC_PCR_NOT_RESETTABLE BASE_RC_BAD_TEMPLATE = lib.TSS2_BASE_RC_BAD_TEMPLATE BASE_RC_AUTHORIZATION_FAILED = lib.TSS2_BASE_RC_AUTHORIZATION_FAILED BASE_RC_AUTHORIZATION_UNKNOWN = lib.TSS2_BASE_RC_AUTHORIZATION_UNKNOWN BASE_RC_NV_NOT_READABLE = lib.TSS2_BASE_RC_NV_NOT_READABLE BASE_RC_NV_TOO_SMALL = lib.TSS2_BASE_RC_NV_TOO_SMALL BASE_RC_NV_NOT_WRITEABLE = lib.TSS2_BASE_RC_NV_NOT_WRITEABLE BASE_RC_POLICY_UNKNOWN = lib.TSS2_BASE_RC_POLICY_UNKNOWN BASE_RC_NV_WRONG_TYPE = lib.TSS2_BASE_RC_NV_WRONG_TYPE BASE_RC_NAME_ALREADY_EXISTS = lib.TSS2_BASE_RC_NAME_ALREADY_EXISTS BASE_RC_NO_TPM = lib.TSS2_BASE_RC_NO_TPM BASE_RC_BAD_KEY = lib.TSS2_BASE_RC_BAD_KEY BASE_RC_NO_HANDLE = lib.TSS2_BASE_RC_NO_HANDLE if _lib_version_atleast("tss2-esapi", "3.0.0"): BASE_RC_NOT_PROVISIONED = lib.TSS2_BASE_RC_NOT_PROVISIONED BASE_RC_ALREADY_PROVISIONED = lib.TSS2_BASE_RC_ALREADY_PROVISIONED LAYER_IMPLEMENTATION_SPECIFIC_OFFSET = lib.TSS2_LAYER_IMPLEMENTATION_SPECIFIC_OFFSET LEVEL_IMPLEMENTATION_SPECIFIC_SHIFT = lib.TSS2_LEVEL_IMPLEMENTATION_SPECIFIC_SHIFT RC_SUCCESS = lib.TSS2_RC_SUCCESS TCTI_RC_GENERAL_FAILURE = lib.TSS2_TCTI_RC_GENERAL_FAILURE TCTI_RC_NOT_IMPLEMENTED = lib.TSS2_TCTI_RC_NOT_IMPLEMENTED TCTI_RC_BAD_CONTEXT = lib.TSS2_TCTI_RC_BAD_CONTEXT TCTI_RC_ABI_MISMATCH = lib.TSS2_TCTI_RC_ABI_MISMATCH TCTI_RC_BAD_REFERENCE = lib.TSS2_TCTI_RC_BAD_REFERENCE TCTI_RC_INSUFFICIENT_BUFFER = lib.TSS2_TCTI_RC_INSUFFICIENT_BUFFER TCTI_RC_BAD_SEQUENCE = lib.TSS2_TCTI_RC_BAD_SEQUENCE TCTI_RC_NO_CONNECTION = lib.TSS2_TCTI_RC_NO_CONNECTION TCTI_RC_TRY_AGAIN = lib.TSS2_TCTI_RC_TRY_AGAIN TCTI_RC_IO_ERROR = lib.TSS2_TCTI_RC_IO_ERROR TCTI_RC_BAD_VALUE = lib.TSS2_TCTI_RC_BAD_VALUE TCTI_RC_NOT_PERMITTED = lib.TSS2_TCTI_RC_NOT_PERMITTED TCTI_RC_MALFORMED_RESPONSE = lib.TSS2_TCTI_RC_MALFORMED_RESPONSE TCTI_RC_NOT_SUPPORTED = lib.TSS2_TCTI_RC_NOT_SUPPORTED TCTI_RC_MEMORY = lib.TSS2_TCTI_RC_MEMORY SYS_RC_GENERAL_FAILURE = lib.TSS2_SYS_RC_GENERAL_FAILURE SYS_RC_ABI_MISMATCH = lib.TSS2_SYS_RC_ABI_MISMATCH SYS_RC_BAD_REFERENCE = lib.TSS2_SYS_RC_BAD_REFERENCE SYS_RC_INSUFFICIENT_BUFFER = lib.TSS2_SYS_RC_INSUFFICIENT_BUFFER SYS_RC_BAD_SEQUENCE = lib.TSS2_SYS_RC_BAD_SEQUENCE SYS_RC_BAD_VALUE = lib.TSS2_SYS_RC_BAD_VALUE SYS_RC_INVALID_SESSIONS = lib.TSS2_SYS_RC_INVALID_SESSIONS SYS_RC_NO_DECRYPT_PARAM = lib.TSS2_SYS_RC_NO_DECRYPT_PARAM SYS_RC_NO_ENCRYPT_PARAM = lib.TSS2_SYS_RC_NO_ENCRYPT_PARAM SYS_RC_BAD_SIZE = lib.TSS2_SYS_RC_BAD_SIZE SYS_RC_MALFORMED_RESPONSE = lib.TSS2_SYS_RC_MALFORMED_RESPONSE SYS_RC_INSUFFICIENT_CONTEXT = lib.TSS2_SYS_RC_INSUFFICIENT_CONTEXT SYS_RC_INSUFFICIENT_RESPONSE = lib.TSS2_SYS_RC_INSUFFICIENT_RESPONSE SYS_RC_INCOMPATIBLE_TCTI = lib.TSS2_SYS_RC_INCOMPATIBLE_TCTI SYS_RC_BAD_TCTI_STRUCTURE = lib.TSS2_SYS_RC_BAD_TCTI_STRUCTURE MU_RC_GENERAL_FAILURE = lib.TSS2_MU_RC_GENERAL_FAILURE MU_RC_BAD_REFERENCE = lib.TSS2_MU_RC_BAD_REFERENCE MU_RC_BAD_SIZE = lib.TSS2_MU_RC_BAD_SIZE MU_RC_BAD_VALUE = lib.TSS2_MU_RC_BAD_VALUE MU_RC_INSUFFICIENT_BUFFER = lib.TSS2_MU_RC_INSUFFICIENT_BUFFER ESYS_RC_GENERAL_FAILURE = lib.TSS2_ESYS_RC_GENERAL_FAILURE ESYS_RC_NOT_IMPLEMENTED = lib.TSS2_ESYS_RC_NOT_IMPLEMENTED ESYS_RC_ABI_MISMATCH = lib.TSS2_ESYS_RC_ABI_MISMATCH ESYS_RC_BAD_REFERENCE = lib.TSS2_ESYS_RC_BAD_REFERENCE ESYS_RC_INSUFFICIENT_BUFFER = lib.TSS2_ESYS_RC_INSUFFICIENT_BUFFER ESYS_RC_BAD_SEQUENCE = lib.TSS2_ESYS_RC_BAD_SEQUENCE ESYS_RC_INVALID_SESSIONS = lib.TSS2_ESYS_RC_INVALID_SESSIONS ESYS_RC_TRY_AGAIN = lib.TSS2_ESYS_RC_TRY_AGAIN ESYS_RC_IO_ERROR = lib.TSS2_ESYS_RC_IO_ERROR ESYS_RC_BAD_VALUE = lib.TSS2_ESYS_RC_BAD_VALUE ESYS_RC_NO_DECRYPT_PARAM = lib.TSS2_ESYS_RC_NO_DECRYPT_PARAM ESYS_RC_NO_ENCRYPT_PARAM = lib.TSS2_ESYS_RC_NO_ENCRYPT_PARAM ESYS_RC_BAD_SIZE = lib.TSS2_ESYS_RC_BAD_SIZE ESYS_RC_MALFORMED_RESPONSE = lib.TSS2_ESYS_RC_MALFORMED_RESPONSE ESYS_RC_INSUFFICIENT_CONTEXT = lib.TSS2_ESYS_RC_INSUFFICIENT_CONTEXT ESYS_RC_INSUFFICIENT_RESPONSE = lib.TSS2_ESYS_RC_INSUFFICIENT_RESPONSE ESYS_RC_INCOMPATIBLE_TCTI = lib.TSS2_ESYS_RC_INCOMPATIBLE_TCTI ESYS_RC_BAD_TCTI_STRUCTURE = lib.TSS2_ESYS_RC_BAD_TCTI_STRUCTURE ESYS_RC_MEMORY = lib.TSS2_ESYS_RC_MEMORY ESYS_RC_BAD_TR = lib.TSS2_ESYS_RC_BAD_TR ESYS_RC_MULTIPLE_DECRYPT_SESSIONS = lib.TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS = lib.TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS ESYS_RC_RSP_AUTH_FAILED = lib.TSS2_ESYS_RC_RSP_AUTH_FAILED if _lib_version_atleast("tss2-fapi", "3.0.0"): FAPI_RC_GENERAL_FAILURE = lib.TSS2_FAPI_RC_GENERAL_FAILURE FAPI_RC_NOT_IMPLEMENTED = lib.TSS2_FAPI_RC_NOT_IMPLEMENTED FAPI_RC_BAD_REFERENCE = lib.TSS2_FAPI_RC_BAD_REFERENCE FAPI_RC_BAD_SEQUENCE = lib.TSS2_FAPI_RC_BAD_SEQUENCE FAPI_RC_IO_ERROR = lib.TSS2_FAPI_RC_IO_ERROR FAPI_RC_BAD_VALUE = lib.TSS2_FAPI_RC_BAD_VALUE FAPI_RC_NO_DECRYPT_PARAM = lib.TSS2_FAPI_RC_NO_DECRYPT_PARAM FAPI_RC_NO_ENCRYPT_PARAM = lib.TSS2_FAPI_RC_NO_ENCRYPT_PARAM FAPI_RC_MEMORY = lib.TSS2_FAPI_RC_MEMORY FAPI_RC_BAD_CONTEXT = lib.TSS2_FAPI_RC_BAD_CONTEXT FAPI_RC_NO_CONFIG = lib.TSS2_FAPI_RC_NO_CONFIG FAPI_RC_BAD_PATH = lib.TSS2_FAPI_RC_BAD_PATH FAPI_RC_NOT_DELETABLE = lib.TSS2_FAPI_RC_NOT_DELETABLE FAPI_RC_PATH_ALREADY_EXISTS = lib.TSS2_FAPI_RC_PATH_ALREADY_EXISTS FAPI_RC_KEY_NOT_FOUND = lib.TSS2_FAPI_RC_KEY_NOT_FOUND FAPI_RC_SIGNATURE_VERIFICATION_FAILED = ( lib.TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED ) FAPI_RC_HASH_MISMATCH = lib.TSS2_FAPI_RC_HASH_MISMATCH FAPI_RC_KEY_NOT_DUPLICABLE = lib.TSS2_FAPI_RC_KEY_NOT_DUPLICABLE FAPI_RC_PATH_NOT_FOUND = lib.TSS2_FAPI_RC_PATH_NOT_FOUND FAPI_RC_NO_CERT = lib.TSS2_FAPI_RC_NO_CERT FAPI_RC_NO_PCR = lib.TSS2_FAPI_RC_NO_PCR FAPI_RC_PCR_NOT_RESETTABLE = lib.TSS2_FAPI_RC_PCR_NOT_RESETTABLE FAPI_RC_BAD_TEMPLATE = lib.TSS2_FAPI_RC_BAD_TEMPLATE FAPI_RC_AUTHORIZATION_FAILED = lib.TSS2_FAPI_RC_AUTHORIZATION_FAILED FAPI_RC_AUTHORIZATION_UNKNOWN = lib.TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN FAPI_RC_NV_NOT_READABLE = lib.TSS2_FAPI_RC_NV_NOT_READABLE FAPI_RC_NV_TOO_SMALL = lib.TSS2_FAPI_RC_NV_TOO_SMALL FAPI_RC_NV_NOT_WRITEABLE = lib.TSS2_FAPI_RC_NV_NOT_WRITEABLE FAPI_RC_POLICY_UNKNOWN = lib.TSS2_FAPI_RC_POLICY_UNKNOWN FAPI_RC_NV_WRONG_TYPE = lib.TSS2_FAPI_RC_NV_WRONG_TYPE FAPI_RC_NAME_ALREADY_EXISTS = lib.TSS2_FAPI_RC_NAME_ALREADY_EXISTS FAPI_RC_NO_TPM = lib.TSS2_FAPI_RC_NO_TPM FAPI_RC_TRY_AGAIN = lib.TSS2_FAPI_RC_TRY_AGAIN FAPI_RC_BAD_KEY = lib.TSS2_FAPI_RC_BAD_KEY FAPI_RC_NO_HANDLE = lib.TSS2_FAPI_RC_NO_HANDLE FAPI_RC_NOT_PROVISIONED = lib.TSS2_FAPI_RC_NOT_PROVISIONED FAPI_RC_ALREADY_PROVISIONED = lib.TSS2_FAPI_RC_ALREADY_PROVISIONED if _lib_version_atleast("tss2-policy", "4.0.0"): POLICY_RC_GENERAL_FAILURE = lib.TSS2_POLICY_RC_GENERAL_FAILURE POLICY_RC_IO_ERROR = lib.TSS2_POLICY_RC_IO_ERROR POLICY_RC_AUTHORIZATION_UNKNOWN = lib.TSS2_POLICY_RC_AUTHORIZATION_UNKNOWN POLICY_RC_BAD_VALUE = lib.TSS2_POLICY_RC_BAD_VALUE POLICY_RC_MEMORY = lib.TSS2_POLICY_RC_MEMORY POLICY_RC_BAD_REFERENCE = lib.TSS2_POLICY_RC_BAD_REFERENCE POLICY_RC_BAD_TEMPLATE = lib.TSS2_POLICY_RC_BAD_TEMPLATE POLICY_RC_POLICY_NOT_CALCULATED = lib.TSS2_POLICY_RC_POLICY_NOT_CALCULATED POLICY_RC_BUFFER_TOO_SMALL = lib.TSS2_POLICY_RC_BUFFER_TOO_SMALL POLICY_RC_NULL_CALLBACK = lib.TSS2_POLICY_RC_NULL_CALLBACK @TPM_FRIENDLY_INT._fix_const_type class TPM2_EO(TPM_FRIENDLY_INT): EQ = lib.TPM2_EO_EQ NEQ = lib.TPM2_EO_NEQ SIGNED_GT = lib.TPM2_EO_SIGNED_GT UNSIGNED_GT = lib.TPM2_EO_UNSIGNED_GT SIGNED_LT = lib.TPM2_EO_SIGNED_LT UNSIGNED_LT = lib.TPM2_EO_UNSIGNED_LT SIGNED_GE = lib.TPM2_EO_SIGNED_GE UNSIGNED_GE = lib.TPM2_EO_UNSIGNED_GE SIGNED_LE = lib.TPM2_EO_SIGNED_LE UNSIGNED_LE = lib.TPM2_EO_UNSIGNED_LE BITSET = lib.TPM2_EO_BITSET BITCLEAR = lib.TPM2_EO_BITCLEAR @TPM_FRIENDLY_INT._fix_const_type class TPM2_ST(TPM_FRIENDLY_INT): RSP_COMMAND = lib.TPM2_ST_RSP_COMMAND NULL = lib.TPM2_ST_NULL NO_SESSIONS = lib.TPM2_ST_NO_SESSIONS SESSIONS = lib.TPM2_ST_SESSIONS ATTEST_NV = lib.TPM2_ST_ATTEST_NV ATTEST_COMMAND_AUDIT = lib.TPM2_ST_ATTEST_COMMAND_AUDIT ATTEST_SESSION_AUDIT = lib.TPM2_ST_ATTEST_SESSION_AUDIT ATTEST_CERTIFY = lib.TPM2_ST_ATTEST_CERTIFY ATTEST_QUOTE = lib.TPM2_ST_ATTEST_QUOTE ATTEST_TIME = lib.TPM2_ST_ATTEST_TIME ATTEST_CREATION = lib.TPM2_ST_ATTEST_CREATION CREATION = lib.TPM2_ST_CREATION VERIFIED = lib.TPM2_ST_VERIFIED AUTH_SECRET = lib.TPM2_ST_AUTH_SECRET HASHCHECK = lib.TPM2_ST_HASHCHECK AUTH_SIGNED = lib.TPM2_ST_AUTH_SIGNED FU_MANIFEST = lib.TPM2_ST_FU_MANIFEST @TPM_FRIENDLY_INT._fix_const_type class TPM2_SU(TPM_FRIENDLY_INT): CLEAR = lib.TPM2_SU_CLEAR STATE = lib.TPM2_SU_STATE @TPM_FRIENDLY_INT._fix_const_type class TPM2_SE(TPM_FRIENDLY_INT): HMAC = lib.TPM2_SE_HMAC POLICY = lib.TPM2_SE_POLICY TRIAL = lib.TPM2_SE_TRIAL @TPM_FRIENDLY_INT._fix_const_type class TPM2_CAP(TPM_FRIENDLY_INT): FIRST = lib.TPM2_CAP_FIRST ALGS = lib.TPM2_CAP_ALGS HANDLES = lib.TPM2_CAP_HANDLES COMMANDS = lib.TPM2_CAP_COMMANDS PP_COMMANDS = lib.TPM2_CAP_PP_COMMANDS AUDIT_COMMANDS = lib.TPM2_CAP_AUDIT_COMMANDS PCRS = lib.TPM2_CAP_PCRS TPM_PROPERTIES = lib.TPM2_CAP_TPM_PROPERTIES PCR_PROPERTIES = lib.TPM2_CAP_PCR_PROPERTIES ECC_CURVES = lib.TPM2_CAP_ECC_CURVES LAST = lib.TPM2_CAP_LAST VENDOR_PROPERTY = lib.TPM2_CAP_VENDOR_PROPERTY @TPM_FRIENDLY_INT._fix_const_type class TPMI_YES_NO(TPM_FRIENDLY_INT): YES = lib.TPM2_YES NO = lib.TPM2_NO @TPM_FRIENDLY_INT._fix_const_type class TPM_AT(TPM_FRIENDLY_INT): ANY = lib.TPM_AT_ANY ERROR = lib.TPM_AT_ERROR PV1 = lib.TPM_AT_PV1 VEND = lib.TPM_AT_VEND @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT(TPM_FRIENDLY_INT): NONE = lib.TPM2_PT_NONE GROUP = lib.TPM2_PT_GROUP FIXED = lib.TPM2_PT_FIXED LOCKOUT_COUNTER = lib.TPM2_PT_LOCKOUT_COUNTER LEVEL = lib.TPM2_PT_LEVEL REVISION = lib.TPM2_PT_REVISION DAY_OF_YEAR = lib.TPM2_PT_DAY_OF_YEAR YEAR = lib.TPM2_PT_YEAR MANUFACTURER = lib.TPM2_PT_MANUFACTURER FAMILY_INDICATOR = lib.TPM2_PT_FAMILY_INDICATOR INPUT_BUFFER = lib.TPM2_PT_INPUT_BUFFER ACTIVE_SESSIONS_MAX = lib.TPM2_PT_ACTIVE_SESSIONS_MAX CONTEXT_GAP_MAX = lib.TPM2_PT_CONTEXT_GAP_MAX MEMORY = lib.TPM2_PT_MEMORY CLOCK_UPDATE = lib.TPM2_PT_CLOCK_UPDATE ORDERLY_COUNT = lib.TPM2_PT_ORDERLY_COUNT MAX_COMMAND_SIZE = lib.TPM2_PT_MAX_COMMAND_SIZE MAX_RESPONSE_SIZE = lib.TPM2_PT_MAX_RESPONSE_SIZE MAX_DIGEST = lib.TPM2_PT_MAX_DIGEST MAX_OBJECT_CONTEXT = lib.TPM2_PT_MAX_OBJECT_CONTEXT MAX_SESSION_CONTEXT = lib.TPM2_PT_MAX_SESSION_CONTEXT SPLIT_MAX = lib.TPM2_PT_SPLIT_MAX TOTAL_COMMANDS = lib.TPM2_PT_TOTAL_COMMANDS VENDOR_COMMANDS = lib.TPM2_PT_VENDOR_COMMANDS MODES = lib.TPM2_PT_MODES VAR = lib.TPM2_PT_VAR PERMANENT = lib.TPM2_PT_PERMANENT STARTUP_CLEAR = lib.TPM2_PT_STARTUP_CLEAR LIBRARY_COMMANDS = lib.TPM2_PT_LIBRARY_COMMANDS ALGORITHM_SET = lib.TPM2_PT_ALGORITHM_SET LOADED_CURVES = lib.TPM2_PT_LOADED_CURVES MAX_AUTH_FAIL = lib.TPM2_PT_MAX_AUTH_FAIL LOCKOUT_INTERVAL = lib.TPM2_PT_LOCKOUT_INTERVAL LOCKOUT_RECOVERY = lib.TPM2_PT_LOCKOUT_RECOVERY @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_VENDOR(TPM_FRIENDLY_INT): STRING_1 = lib.TPM2_PT_VENDOR_STRING_1 STRING_2 = lib.TPM2_PT_VENDOR_STRING_2 STRING_3 = lib.TPM2_PT_VENDOR_STRING_3 STRING_4 = lib.TPM2_PT_VENDOR_STRING_4 TPM_TYPE = lib.TPM2_PT_VENDOR_TPM_TYPE @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_FIRMWARE(TPM_FRIENDLY_INT): VERSION_1 = lib.TPM2_PT_FIRMWARE_VERSION_1 VERSION_2 = lib.TPM2_PT_FIRMWARE_VERSION_2 @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_HR(TPM_FRIENDLY_INT): LOADED_MIN = lib.TPM2_PT_HR_LOADED_MIN NV_INDEX = lib.TPM2_PT_HR_NV_INDEX LOADED = lib.TPM2_PT_HR_LOADED LOADED_AVAIL = lib.TPM2_PT_HR_LOADED_AVAIL ACTIVE = lib.TPM2_PT_HR_ACTIVE ACTIVE_AVAIL = lib.TPM2_PT_HR_ACTIVE_AVAIL TRANSIENT_AVAIL = lib.TPM2_PT_HR_TRANSIENT_AVAIL PERSISTENT = lib.TPM2_PT_HR_PERSISTENT PERSISTENT_AVAIL = lib.TPM2_PT_HR_PERSISTENT_AVAIL TRANSIENT_MIN = lib.TPM2_PT_HR_TRANSIENT_MIN PERSISTENT_MIN = lib.TPM2_PT_HR_PERSISTENT_MIN @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_NV(TPM_FRIENDLY_INT): COUNTERS_MAX = lib.TPM2_PT_NV_COUNTERS_MAX INDEX_MAX = lib.TPM2_PT_NV_INDEX_MAX BUFFER_MAX = lib.TPM2_PT_NV_BUFFER_MAX COUNTERS = lib.TPM2_PT_NV_COUNTERS COUNTERS_AVAIL = lib.TPM2_PT_NV_COUNTERS_AVAIL WRITE_RECOVERY = lib.TPM2_PT_NV_WRITE_RECOVERY @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_CONTEXT(TPM_FRIENDLY_INT): HASH = lib.TPM2_PT_CONTEXT_HASH SYM = lib.TPM2_PT_CONTEXT_SYM SYM_SIZE = lib.TPM2_PT_CONTEXT_SYM_SIZE @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_PS(TPM_FRIENDLY_INT): FAMILY_INDICATOR = lib.TPM2_PT_PS_FAMILY_INDICATOR LEVEL = lib.TPM2_PT_PS_LEVEL REVISION = lib.TPM2_PT_PS_REVISION DAY_OF_YEAR = lib.TPM2_PT_PS_DAY_OF_YEAR YEAR = lib.TPM2_PT_PS_YEAR @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_AUDIT(TPM_FRIENDLY_INT): COUNTER_0 = lib.TPM2_PT_AUDIT_COUNTER_0 COUNTER_1 = lib.TPM2_PT_AUDIT_COUNTER_1 @TPM_FRIENDLY_INT._fix_const_type class TPM2_PT_PCR(TPM_FRIENDLY_INT): FIRST = lib.TPM2_PT_TPM2_PCR_FIRST SAVE = lib.TPM2_PT_PCR_SAVE EXTEND_L0 = lib.TPM2_PT_PCR_EXTEND_L0 RESET_L0 = lib.TPM2_PT_PCR_RESET_L0 EXTEND_L1 = lib.TPM2_PT_PCR_EXTEND_L1 RESET_L1 = lib.TPM2_PT_PCR_RESET_L1 EXTEND_L2 = lib.TPM2_PT_PCR_EXTEND_L2 RESET_L2 = lib.TPM2_PT_PCR_RESET_L2 EXTEND_L3 = lib.TPM2_PT_PCR_EXTEND_L3 RESET_L3 = lib.TPM2_PT_PCR_RESET_L3 EXTEND_L4 = lib.TPM2_PT_PCR_EXTEND_L4 RESET_L4 = lib.TPM2_PT_PCR_RESET_L4 NO_INCREMENT = lib.TPM2_PT_PCR_NO_INCREMENT DRTM_RESET = lib.TPM2_PT_PCR_DRTM_RESET POLICY = lib.TPM2_PT_PCR_POLICY AUTH = lib.TPM2_PT_PCR_AUTH LAST = lib.TPM2_PT_TPM2_PCR_LAST COUNT = lib.TPM2_PT_PCR_COUNT SELECT_MIN = lib.TPM2_PT_PCR_SELECT_MIN @TPM_FRIENDLY_INT._fix_const_type class TPM2_PS(TPM_FRIENDLY_INT): MAIN = lib.TPM2_PS_MAIN PC = lib.TPM2_PS_PC PDA = lib.TPM2_PS_PDA CELL_PHONE = lib.TPM2_PS_CELL_PHONE SERVER = lib.TPM2_PS_SERVER PERIPHERAL = lib.TPM2_PS_PERIPHERAL TSS = lib.TPM2_PS_TSS STORAGE = lib.TPM2_PS_STORAGE AUTHENTICATION = lib.TPM2_PS_AUTHENTICATION EMBEDDED = lib.TPM2_PS_EMBEDDED HARDCOPY = lib.TPM2_PS_HARDCOPY INFRASTRUCTURE = lib.TPM2_PS_INFRASTRUCTURE VIRTUALIZATION = lib.TPM2_PS_VIRTUALIZATION TNC = lib.TPM2_PS_TNC MULTI_TENANT = lib.TPM2_PS_MULTI_TENANT TC = lib.TPM2_PS_TC @TPM_FRIENDLY_INT._fix_const_type class TPM2_HT(TPM_FRIENDLY_INT): PCR = lib.TPM2_HT_PCR NV_INDEX = lib.TPM2_HT_NV_INDEX HMAC_SESSION = lib.TPM2_HT_HMAC_SESSION LOADED_SESSION = lib.TPM2_HT_LOADED_SESSION POLICY_SESSION = lib.TPM2_HT_POLICY_SESSION SAVED_SESSION = lib.TPM2_HT_SAVED_SESSION PERMANENT = lib.TPM2_HT_PERMANENT TRANSIENT = lib.TPM2_HT_TRANSIENT PERSISTENT = lib.TPM2_HT_PERSISTENT @TPM_FRIENDLY_INT._fix_const_type class TPMA_SESSION(TPMA_FRIENDLY_INTLIST): CONTINUESESSION = lib.TPMA_SESSION_CONTINUESESSION AUDITEXCLUSIVE = lib.TPMA_SESSION_AUDITEXCLUSIVE AUDITRESET = lib.TPMA_SESSION_AUDITRESET DECRYPT = lib.TPMA_SESSION_DECRYPT ENCRYPT = lib.TPMA_SESSION_ENCRYPT AUDIT = lib.TPMA_SESSION_AUDIT @TPM_FRIENDLY_INT._fix_const_type class TPMA_LOCALITY(TPMA_FRIENDLY_INTLIST): ZERO = lib.TPMA_LOCALITY_TPM2_LOC_ZERO ONE = lib.TPMA_LOCALITY_TPM2_LOC_ONE TWO = lib.TPMA_LOCALITY_TPM2_LOC_TWO THREE = lib.TPMA_LOCALITY_TPM2_LOC_THREE FOUR = lib.TPMA_LOCALITY_TPM2_LOC_FOUR EXTENDED_MASK = lib.TPMA_LOCALITY_EXTENDED_MASK EXTENDED_SHIFT = lib.TPMA_LOCALITY_EXTENDED_SHIFT @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__() @TPM_FRIENDLY_INT._fix_const_type class TPM2_NT(TPM_FRIENDLY_INT): ORDINARY = lib.TPM2_NT_ORDINARY COUNTER = lib.TPM2_NT_COUNTER BITS = lib.TPM2_NT_BITS EXTEND = lib.TPM2_NT_EXTEND PIN_FAIL = lib.TPM2_NT_PIN_FAIL PIN_PASS = lib.TPM2_NT_PIN_PASS @TPM_FRIENDLY_INT._fix_const_type class TPM2_HR(TPM_FRIENDLY_INT): HANDLE_MASK = lib.TPM2_HR_HANDLE_MASK RANGE_MASK = lib.TPM2_HR_RANGE_MASK SHIFT = lib.TPM2_HR_SHIFT PCR = lib.TPM2_HR_PCR HMAC_SESSION = lib.TPM2_HR_HMAC_SESSION POLICY_SESSION = lib.TPM2_HR_POLICY_SESSION TRANSIENT = lib.TPM2_HR_TRANSIENT PERSISTENT = lib.TPM2_HR_PERSISTENT NV_INDEX = lib.TPM2_HR_NV_INDEX PERMANENT = lib.TPM2_HR_PERMANENT @TPM_FRIENDLY_INT._fix_const_type class TPM2_HC(TPM_FRIENDLY_INT): HR_HANDLE_MASK = lib.TPM2_HR_HANDLE_MASK HR_RANGE_MASK = lib.TPM2_HR_RANGE_MASK HR_SHIFT = lib.TPM2_HR_SHIFT HR_PCR = lib.TPM2_HR_PCR HR_HMAC_SESSION = lib.TPM2_HR_HMAC_SESSION HR_POLICY_SESSION = lib.TPM2_HR_POLICY_SESSION HR_TRANSIENT = lib.TPM2_HR_TRANSIENT HR_PERSISTENT = lib.TPM2_HR_PERSISTENT HR_NV_INDEX = lib.TPM2_HR_NV_INDEX HR_PERMANENT = lib.TPM2_HR_PERMANENT PCR_FIRST = lib.TPM2_PCR_FIRST PCR_LAST = lib.TPM2_PCR_LAST HMAC_SESSION_FIRST = lib.TPM2_HMAC_SESSION_FIRST HMAC_SESSION_LAST = lib.TPM2_HMAC_SESSION_LAST LOADED_SESSION_FIRST = lib.TPM2_LOADED_SESSION_FIRST LOADED_SESSION_LAST = lib.TPM2_LOADED_SESSION_LAST POLICY_SESSION_FIRST = lib.TPM2_POLICY_SESSION_FIRST POLICY_SESSION_LAST = lib.TPM2_POLICY_SESSION_LAST TRANSIENT_FIRST = lib.TPM2_TRANSIENT_FIRST ACTIVE_SESSION_FIRST = lib.TPM2_ACTIVE_SESSION_FIRST ACTIVE_SESSION_LAST = lib.TPM2_ACTIVE_SESSION_LAST TRANSIENT_LAST = lib.TPM2_TRANSIENT_LAST PERSISTENT_FIRST = lib.TPM2_PERSISTENT_FIRST PERSISTENT_LAST = lib.TPM2_PERSISTENT_LAST PLATFORM_PERSISTENT = lib.TPM2_PLATFORM_PERSISTENT NV_INDEX_FIRST = lib.TPM2_NV_INDEX_FIRST NV_INDEX_LAST = lib.TPM2_NV_INDEX_LAST PERMANENT_FIRST = lib.TPM2_PERMANENT_FIRST PERMANENT_LAST = lib.TPM2_PERMANENT_LAST @TPM_FRIENDLY_INT._fix_const_type class TPM2_CLOCK(TPM_FRIENDLY_INT): COARSE_SLOWER = lib.TPM2_CLOCK_COARSE_SLOWER MEDIUM_SLOWER = lib.TPM2_CLOCK_MEDIUM_SLOWER FINE_SLOWER = lib.TPM2_CLOCK_FINE_SLOWER NO_CHANGE = lib.TPM2_CLOCK_NO_CHANGE FINE_FASTER = lib.TPM2_CLOCK_FINE_FASTER MEDIUM_FASTER = lib.TPM2_CLOCK_MEDIUM_FASTER COARSE_FASTER = lib.TPM2_CLOCK_COARSE_FASTER @TPM_FRIENDLY_INT._fix_const_type class TPM2_CLOCK_ADJUST(TPM2_CLOCK): pass @TPM_FRIENDLY_INT._fix_const_type class TPMA_NV(TPMA_FRIENDLY_INTLIST): _FIXUP_MAP = {"NODA": "NO_DA"} _MASKS = ((lib.TPMA_NV_TPM2_NT_MASK, lib.TPMA_NV_TPM2_NT_SHIFT, "nt"),) PPWRITE = lib.TPMA_NV_PPWRITE OWNERWRITE = lib.TPMA_NV_OWNERWRITE AUTHWRITE = lib.TPMA_NV_AUTHWRITE POLICYWRITE = lib.TPMA_NV_POLICYWRITE TPM2_NT_MASK = lib.TPMA_NV_TPM2_NT_MASK TPM2_NT_SHIFT = lib.TPMA_NV_TPM2_NT_SHIFT POLICY_DELETE = lib.TPMA_NV_POLICY_DELETE WRITELOCKED = lib.TPMA_NV_WRITELOCKED WRITEALL = lib.TPMA_NV_WRITEALL WRITEDEFINE = lib.TPMA_NV_WRITEDEFINE WRITE_STCLEAR = lib.TPMA_NV_WRITE_STCLEAR GLOBALLOCK = lib.TPMA_NV_GLOBALLOCK PPREAD = lib.TPMA_NV_PPREAD OWNERREAD = lib.TPMA_NV_OWNERREAD AUTHREAD = lib.TPMA_NV_AUTHREAD POLICYREAD = lib.TPMA_NV_POLICYREAD NO_DA = lib.TPMA_NV_NO_DA ORDERLY = lib.TPMA_NV_ORDERLY CLEAR_STCLEAR = lib.TPMA_NV_CLEAR_STCLEAR READLOCKED = lib.TPMA_NV_READLOCKED WRITTEN = lib.TPMA_NV_WRITTEN PLATFORMCREATE = lib.TPMA_NV_PLATFORMCREATE READ_STCLEAR = lib.TPMA_NV_READ_STCLEAR @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) @TPM_FRIENDLY_INT._fix_const_type class TPMA_CC(TPMA_FRIENDLY_INTLIST): _MASKS = ( (lib.TPMA_CC_COMMANDINDEX_MASK, lib.TPMA_CC_COMMANDINDEX_SHIFT, "commandindex"), (lib.TPMA_CC_CHANDLES_MASK, lib.TPMA_CC_CHANDLES_SHIFT, "chandles"), ) COMMANDINDEX_MASK = lib.TPMA_CC_COMMANDINDEX_MASK COMMANDINDEX_SHIFT = lib.TPMA_CC_COMMANDINDEX_SHIFT RESERVED1_MASK = lib.TPMA_CC_RESERVED1_MASK NV = lib.TPMA_CC_NV EXTENSIVE = lib.TPMA_CC_EXTENSIVE FLUSHED = lib.TPMA_CC_FLUSHED CHANDLES_MASK = lib.TPMA_CC_CHANDLES_MASK CHANDLES_SHIFT = lib.TPMA_CC_CHANDLES_SHIFT RHANDLE = lib.TPMA_CC_RHANDLE V = lib.TPMA_CC_V RES_MASK = lib.TPMA_CC_RES_MASK RES_SHIFT = lib.TPMA_CC_RES_SHIFT @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 @TPM_FRIENDLY_INT._fix_const_type class TPMA_OBJECT(TPMA_FRIENDLY_INTLIST): FIXEDTPM = lib.TPMA_OBJECT_FIXEDTPM STCLEAR = lib.TPMA_OBJECT_STCLEAR FIXEDPARENT = lib.TPMA_OBJECT_FIXEDPARENT SENSITIVEDATAORIGIN = lib.TPMA_OBJECT_SENSITIVEDATAORIGIN USERWITHAUTH = lib.TPMA_OBJECT_USERWITHAUTH ADMINWITHPOLICY = lib.TPMA_OBJECT_ADMINWITHPOLICY NODA = lib.TPMA_OBJECT_NODA ENCRYPTEDDUPLICATION = lib.TPMA_OBJECT_ENCRYPTEDDUPLICATION RESTRICTED = lib.TPMA_OBJECT_RESTRICTED DECRYPT = lib.TPMA_OBJECT_DECRYPT SIGN_ENCRYPT = lib.TPMA_OBJECT_SIGN_ENCRYPT DEFAULT_TPM2_TOOLS_CREATE_ATTRS = ( lib.TPMA_OBJECT_DECRYPT | lib.TPMA_OBJECT_SIGN_ENCRYPT | lib.TPMA_OBJECT_FIXEDTPM | lib.TPMA_OBJECT_FIXEDPARENT | lib.TPMA_OBJECT_SENSITIVEDATAORIGIN | lib.TPMA_OBJECT_USERWITHAUTH ) DEFAULT_TPM2_TOOLS_CREATEPRIMARY_ATTRS = ( lib.TPMA_OBJECT_RESTRICTED | lib.TPMA_OBJECT_DECRYPT | lib.TPMA_OBJECT_FIXEDTPM | lib.TPMA_OBJECT_FIXEDPARENT | lib.TPMA_OBJECT_SENSITIVEDATAORIGIN | lib.TPMA_OBJECT_USERWITHAUTH ) _FIXUP_MAP = { "SIGN": "SIGN_ENCRYPT", "ENCRYPT": "SIGN_ENCRYPT", } @TPM_FRIENDLY_INT._fix_const_type class TPMA_ALGORITHM(TPM_FRIENDLY_INT): ASYMMETRIC = lib.TPMA_ALGORITHM_ASYMMETRIC SYMMETRIC = lib.TPMA_ALGORITHM_SYMMETRIC HASH = lib.TPMA_ALGORITHM_HASH OBJECT = lib.TPMA_ALGORITHM_OBJECT RESERVED1_MASK = lib.TPMA_ALGORITHM_RESERVED1_MASK SIGNING = lib.TPMA_ALGORITHM_SIGNING ENCRYPTING = lib.TPMA_ALGORITHM_ENCRYPTING METHOD = lib.TPMA_ALGORITHM_METHOD @TPM_FRIENDLY_INT._fix_const_type class TPMA_PERMANENT(TPMA_FRIENDLY_INTLIST): OWNERAUTHSET = lib.TPMA_PERMANENT_OWNERAUTHSET ENDORSEMENTAUTHSET = lib.TPMA_PERMANENT_ENDORSEMENTAUTHSET LOCKOUTAUTHSET = lib.TPMA_PERMANENT_LOCKOUTAUTHSET RESERVED1_MASK = lib.TPMA_PERMANENT_RESERVED1_MASK DISABLECLEAR = lib.TPMA_PERMANENT_DISABLECLEAR INLOCKOUT = lib.TPMA_PERMANENT_INLOCKOUT TPMGENERATEDEPS = lib.TPMA_PERMANENT_TPMGENERATEDEPS RESERVED2_MASK = lib.TPMA_PERMANENT_RESERVED2_MASK @TPM_FRIENDLY_INT._fix_const_type class TPMA_STARTUP(TPMA_FRIENDLY_INTLIST): CLEAR_PHENABLE = lib.TPMA_STARTUP_CLEAR_PHENABLE CLEAR_SHENABLE = lib.TPMA_STARTUP_CLEAR_SHENABLE CLEAR_EHENABLE = lib.TPMA_STARTUP_CLEAR_EHENABLE CLEAR_PHENABLENV = lib.TPMA_STARTUP_CLEAR_PHENABLENV CLEAR_RESERVED1_MASK = lib.TPMA_STARTUP_CLEAR_RESERVED1_MASK CLEAR_ORDERLY = lib.TPMA_STARTUP_CLEAR_ORDERLY @TPM_FRIENDLY_INT._fix_const_type class TPMA_MEMORY(TPM_FRIENDLY_INT): SHAREDRAM = lib.TPMA_MEMORY_SHAREDRAM SHAREDNV = lib.TPMA_MEMORY_SHAREDNV OBJECTCOPIEDTORAM = lib.TPMA_MEMORY_OBJECTCOPIEDTORAM @TPM_FRIENDLY_INT._fix_const_type class TPM2_MAX(TPM_FRIENDLY_INT): DIGEST_BUFFER = lib.TPM2_MAX_DIGEST_BUFFER NV_BUFFER_SIZE = lib.TPM2_MAX_NV_BUFFER_SIZE PCRS = lib.TPM2_MAX_PCRS ALG_LIST_SIZE = lib.TPM2_MAX_ALG_LIST_SIZE CAP_CC = lib.TPM2_MAX_CAP_CC CAP_BUFFER = lib.TPM2_MAX_CAP_BUFFER CONTEXT_SIZE = lib.TPM2_MAX_CONTEXT_SIZE @TPM_FRIENDLY_INT._fix_const_type class TPMA_MODES(TPMA_FRIENDLY_INTLIST): FIPS_140_2 = lib.TPMA_MODES_FIPS_140_2 RESERVED1_MASK = lib.TPMA_MODES_RESERVED1_MASK # # 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. # @TPM_FRIENDLY_INT._fix_const_type class FAPI_ESYSBLOB(TPM_FRIENDLY_INT): CONTEXTLOAD = 1 DESERIALIZE = 2 @TPM_FRIENDLY_INT._fix_const_type class TSS2_POLICY_PCR_SELECTOR(TPM_FRIENDLY_INT): PCR_SELECT = 0 PCR_SELECTION = 1 tpm2-pytss-2.3.0/src/tpm2_pytss/cryptography.py000066400000000000000000000406001463722220500216010ustar00rootroot00000000000000# 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() 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() tpm2-pytss-2.3.0/src/tpm2_pytss/encoding.py000066400000000000000000001731021463722220500206400ustar00rootroot00000000000000from binascii import hexlify, unhexlify from typing import Any, Union, List, Dict, Tuple from ._libtpm2_pytss import ffi from .internal.crypto import _get_digest_size from .constants import ( TPM_FRIENDLY_INT, TPMA_FRIENDLY_INTLIST, TPM2_CAP, TPM2_ST, TPM2_ALG, TPMA_NV, TPMA_CC, TPM2_NT, TPMA_LOCALITY, TPMA_ALGORITHM, TPM2_CC, TPM2_PT, TPM2_PT_VENDOR, TPMA_MODES, TPM2_PT_FIRMWARE, TPM2_PT_HR, TPM2_PT_NV, TPM2_PT_CONTEXT, TPM2_PT_PS, TPM2_PT_AUDIT, TPM2_PT_PCR, TPMA_PERMANENT, TPMA_STARTUP, TPM2_ECC, TPM2_RH, TPMA_OBJECT, TPMA_SESSION, ) 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, TPMS_NV_PUBLIC, TPMS_ALG_PROPERTY, TPML_PCR_SELECTION, TPMS_PCR_SELECTION, TPML_TAGGED_TPM_PROPERTY, TPML_ALG_PROPERTY, TPML_CCA, TPMS_TAGGED_PROPERTY, TPML_ECC_CURVE, TPML_HANDLE, TPMS_CLOCK_INFO, TPMS_CONTEXT, TPM2_HANDLE, TPM2B_DIGEST, TPML_DIGEST, TPML_DIGEST_VALUES, TPMU_HA, TPML_ALG, TPM2B_NAME, TPMS_NV_PIN_COUNTER_PARAMETERS, ) import yaml import collections.abc import warnings 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_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_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 type(val).contains(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 type(val).contains(c) 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 class tools_encdec(base_encdec): """Encode TPM types in the same format as tpm2-tools """ def __init__(self): warnings.warn( "The tools_encdec class will be deprecated in the future, " "see https://github.com/tpm2-software/tpm2-pytss/issues/557", category=PendingDeprecationWarning, ) super().__init__() def encode_friendly_int_nv(self, val: TPM_FRIENDLY_INT) -> Dict[str, str]: d = { "friendly": str(val), "value": int(val), } if isinstance(val, TPM2_ALG) and d["friendly"] == "sha": d["friendly"] = "sha1" return d def encode_friendly_intlist_nv(self, val: TPMA_FRIENDLY_INTLIST) -> Dict[str, str]: return { "friendly": str(val), "value": int(val), } def encode_friendly_int(self, val: TPM_FRIENDLY_INT) -> Dict[str, Any]: d = { "value": str(val), "raw": int(val), } if isinstance(val, TPM2_ALG) and d["value"] == "sha": d["value"] = "sha1" elif isinstance(val, TPM2_ALG) and d["value"] == "null": d["value"] = None return d def encode_tpma_cc(self, val: TPMA_CC) -> Dict[str, Any]: cc = val & TPMA_CC.COMMANDINDEX_MASK ccname = None for attr in dir(TPM2_CC): if getattr(TPM2_CC, attr) == cc: ccname = f"TPM2_CC_{attr}" break if ccname is None: ccname = f"{cc:#x}" d = dict() d["value"] = int(val) d["commandIndex"] = int(cc) reserved1 = (val & TPMA_CC.RESERVED1_MASK) >> 16 d["reserved1"] = int(reserved1) d["nv"] = 1 if val & TPMA_CC.NV else 0 d["extensive"] = 1 if val & TPMA_CC.EXTENSIVE else 0 d["flushed"] = 1 if val & TPMA_CC.FLUSHED else 0 chandles = (val & TPMA_CC.CHANDLES_MASK) >> TPMA_CC.CHANDLES_SHIFT d["cHandles"] = int(chandles) d["rHandle"] = 1 if val & TPMA_CC.RHANDLE else 0 d["V"] = 1 if val & TPMA_CC.V else 0 res = (val & TPMA_CC.RES_MASK) >> TPMA_CC.RES_SHIFT d["Res"] = int(res) return {ccname: d} def encode_tpma_permanent(self, val: TPMA_PERMANENT) -> Dict[str, int]: d = dict() d["ownerAuthSet"] = 1 if val & TPMA_PERMANENT.OWNERAUTHSET else 0 d["endorsementAuthSet"] = 1 if val & TPMA_PERMANENT.ENDORSEMENTAUTHSET else 0 d["lockoutAuthSet"] = 1 if val & TPMA_PERMANENT.LOCKOUTAUTHSET else 0 d["reserved1"] = 1 if val & TPMA_PERMANENT.RESERVED1_MASK else 0 d["disableClear"] = 1 if val & TPMA_PERMANENT.DISABLECLEAR else 0 d["inLockout"] = 1 if val & TPMA_PERMANENT.INLOCKOUT else 0 d["tpmGeneratedEPS"] = 1 if val & TPMA_PERMANENT.TPMGENERATEDEPS else 0 d["reserved2"] = 1 if val & TPMA_PERMANENT.RESERVED2_MASK else 0 return d def encode_tpma_startup_clear(self, val: TPMA_STARTUP) -> Dict[str, int]: d = dict() d["phEnable"] = 1 if val & TPMA_STARTUP.CLEAR_PHENABLE else 0 d["shEnable"] = 1 if val & TPMA_STARTUP.CLEAR_SHENABLE else 0 d["ehEnable"] = 1 if val & TPMA_STARTUP.CLEAR_EHENABLE else 0 d["phEnableNV"] = 1 if val & TPMA_STARTUP.CLEAR_PHENABLENV else 0 d["reserved1"] = 1 if val & TPMA_STARTUP.CLEAR_RESERVED1_MASK else 0 d["orderly"] = 1 if val & TPMA_STARTUP.CLEAR_ORDERLY else 0 return d def encode_tpma_session(self, val: TPMA_SESSION) -> Dict[str, str]: attrs = str(val) return {"Session-Attributes": attrs} def encode_friendly_intlist(self, val: TPMA_FRIENDLY_INTLIST) -> Dict[str, Any]: if isinstance(val, TPMA_CC): return self.encode_tpma_cc(val) elif isinstance(val, TPMA_PERMANENT): return self.encode_tpma_permanent(val) elif isinstance(val, TPMA_STARTUP): return self.encode_tpma_startup_clear(val) elif isinstance(val, TPMA_SESSION): return self.encode_tpma_session(val) return { "value": str(val), "raw": int(val), } def encode_tpms_nv_public(self, val: TPMS_NV_PUBLIC) -> Dict[str, Any]: d = dict() d["name"] = hexlify(val.get_name().name).decode("ascii") d["hash algorithm"] = self.encode_friendly_int_nv(val.nameAlg) d["attributes"] = self.encode_friendly_intlist_nv(val.attributes) d["size"] = self.encode_int(val.dataSize) if val.authPolicy.size: d["authorization policy"] = self.encode(val.authPolicy).upper() return {int(val.nvIndex): d} def encode_tpmt_sym_def( self, val: Union[TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT] ) -> Dict[str, Any]: d = dict() d["sym-alg"] = self.encode(val.algorithm) d["sym-mode"] = self.encode(val.mode.sym) d["sym-keybits"] = self.encode(val.keyBits.sym) return d def encode_tpmt_public(self, val: TPMT_PUBLIC) -> Dict[str, Any]: d = dict() params = self._get_by_selector(val, "parameters") unique = self._get_by_selector(val, "unique") keydata = None d["name-alg"] = self.encode(val.nameAlg) d["attributes"] = self.encode(val.objectAttributes) d["type"] = self.encode(val.type) if val.type == TPM2_ALG.SYMCIPHER: sd = self.encode(params.sym) d.update(sd) keydata = self.encode(unique) elif val.type == TPM2_ALG.KEYEDHASH: details = self._get_by_selector(params.scheme, "scheme") d["hash-alg"] = self.encode(details.hashAlg) if params.scheme == TPM2_ALG.XOR: d["kdfa-alg"] = self.encode(details.kdf) elif val.type == TPM2_ALG.RSA: e = 65537 if not params.exponent else params.exponent d["exponent"] = self.encode(e) d["bits"] = self.encode(params.keyBits) d["scheme"] = self.encode(params.scheme.scheme) if params.scheme.scheme != TPM2_ALG.RSAES: d["scheme-halg"] = self.encode(params.scheme.details.anySig.hashAlg) sd = self.encode(params.symmetric) d.update(sd) keydata = self.encode(unique) elif val.type == TPM2_ALG.ECC: d["curve-id"] = self.encode(params.curveID) d["kdfa-alg"] = self.encode(params.kdf.scheme) d["kdfa-halg"] = self.encode(params.kdf.details.mgf1.hashAlg) d["scheme"] = self.encode(params.scheme.scheme) d["scheme-halg"] = self.encode(params.scheme.details.anySig.hashAlg) if params.scheme.scheme == TPM2_ALG.ECDAA: d["scheme-count"] = self.encode(params.scheme.details.ecdaa.count) sd = self.encode(params.symmetric) d.update(sd) keydata = { "x": self.encode(unique.x), "y": self.encode(unique.y), } if keydata and val.type == TPM2_ALG.ECC: d.update(keydata) elif keydata: d[str(val.type)] = keydata if val.authPolicy.size: d["authorization policy"] = self.encode(val.authPolicy) return d def encode_tpms_alg_property(self, val: TPMS_ALG_PROPERTY) -> Dict[str, Any]: d = dict() d["value"] = int(val.alg) d["asymmetric"] = 1 if val.algProperties & TPMA_ALGORITHM.ASYMMETRIC else 0 d["symmetric"] = 1 if val.algProperties & TPMA_ALGORITHM.SYMMETRIC else 0 d["hash"] = 1 if val.algProperties & TPMA_ALGORITHM.HASH else 0 d["object"] = 1 if val.algProperties & TPMA_ALGORITHM.OBJECT else 0 reserved = (val.algProperties & TPMA_ALGORITHM.RESERVED1_MASK) >> 4 d["reserved"] = int(reserved) d["signing"] = 1 if val.algProperties & TPMA_ALGORITHM.SIGNING else 0 d["encrypting"] = 1 if val.algProperties & TPMA_ALGORITHM.ENCRYPTING else 0 d["method"] = 1 if val.algProperties & TPMA_ALGORITHM.METHOD else 0 algname = str(val.alg) return {algname: d} def encode_tpms_pcr_selection(self, val: TPMS_PCR_SELECTION) -> Dict[str, List]: pcrsel = list() pb = reversed(bytes(val.pcrSelect[0 : val.sizeofSelect])) pi = int.from_bytes(pb, "big") algname = str(val.hash) if algname == "sha": algname = "sha1" i = 0 for i in range(0, val.sizeofSelect * 8): if (1 << i) & pi: pcrsel.append(i) return {algname: pcrsel} def _build_pt_map(self) -> Dict[int, str]: pmap = dict() for attr in dir(TPM2_PT): pa = getattr(TPM2_PT, attr) if not isinstance(pa, int) or attr in ("GROUP", "FIXED", "VAR"): continue pan = f"TPM2_PT_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_VENDOR): pa = getattr(TPM2_PT_VENDOR, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_VENDOR_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_FIRMWARE): pa = getattr(TPM2_PT_FIRMWARE, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_FIRMWARE_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_HR): pa = getattr(TPM2_PT_HR, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_HR_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_NV): pa = getattr(TPM2_PT_NV, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_NV_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_CONTEXT): pa = getattr(TPM2_PT_CONTEXT, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_CONTEXT_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_PS): pa = getattr(TPM2_PT_PS, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_PS_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_AUDIT): pa = getattr(TPM2_PT_AUDIT, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_AUDIT_{attr}" pmap[pa] = pan for attr in dir(TPM2_PT_PCR): pa = getattr(TPM2_PT_PCR, attr) if not isinstance(pa, int): continue pan = f"TPM2_PT_PCR_{attr}" pmap[pa] = pan return pmap def encode_tpms_tagged_property(self, val: TPMS_TAGGED_PROPERTY) -> Dict[str, Any]: p = val.property pmap = self._build_pt_map() pname = pmap.get(p, None) if pname is None: raise ValueError(f"Unsupported property {p}") d = dict() if p == TPM2_PT.LEVEL: d["raw"] = val.value elif p & TPM2_PT.FIXED: d["raw"] = val.value if p == TPM2_PT.REVISION: v = val.value / 100 d["value"] = v elif p in ( TPM2_PT.FAMILY_INDICATOR, TPM2_PT.MANUFACTURER, TPM2_PT_VENDOR.STRING_1, TPM2_PT_VENDOR.STRING_2, TPM2_PT_VENDOR.STRING_3, TPM2_PT_VENDOR.STRING_4, ): b = val.value.to_bytes(4, "big") d["value"] = b.rstrip(b"\x00").decode("ascii") elif p == TPM2_PT.MODES: if val.value & TPMA_MODES.FIPS_140_2: d["value"] = "TPMA_MODES_FIPS_140_2" elif val.value & TPMA_MODES.RESERVED1_MASK: d["value"] = "TPMA_MODES_RESERVED1 (these bits shouldn't be set)" elif p == TPM2_PT.PERMANENT: d = self.encode(TPMA_PERMANENT(val.value)) elif p == TPM2_PT.STARTUP_CLEAR: d = self.encode(TPMA_STARTUP(val.value)) elif p & TPM2_PT.VAR: d = val.value return {pname: d} def encode_tpms_clock_info(self, val: TPMS_CLOCK_INFO) -> Dict[str, int]: d = dict() d["clock"] = val.clock d["resetCount"] = val.resetCount d["restartCount"] = val.restartCount d["safe"] = val.safe return d def encode_tpms_context(self, val: TPMS_CONTEXT) -> Dict[str, Any]: d = dict() d["version"] = 1 if val.hierarchy in (TPM2_RH.OWNER, TPM2_RH.PLATFORM, TPM2_RH.ENDORSEMENT): d["hierarchy"] = str(val.hierarchy) else: d["hierarchy"] = "null" d["handle"] = f"0x{val.savedHandle:X} ({val.savedHandle:d})" d["sequence"] = val.sequence d["contextBlob"] = {"size": val.contextBlob.size} return d def encode_tpms_nv_pin_counter_parameters( self, val: TPMS_NV_PIN_COUNTER_PARAMETERS ) -> Dict[str, int]: d = dict() d["pinCount"] = val.pinCount d["pinLimit"] = val.pinLimit return d def encode_tpml_tagged_tpm_property( self, val: TPML_TAGGED_TPM_PROPERTY ) -> Dict[str, Any]: d = dict() for tp in val: ep = self.encode(tp) d.update(ep) return d def encode_tpml_pcr_selection(self, val: TPML_PCR_SELECTION) -> Dict[str, List]: sels = list() for sel in val: es = self.encode(sel) sels.append(es) return {"selected-pcrs": sels} def encode_tpml_ecc_curve(self, val: TPML_ECC_CURVE) -> Dict[str, str]: d = dict() emap = dict() for attr in dir(TPM2_ECC): ev = getattr(TPM2_ECC, attr) if not isinstance(ev, int): continue en = f"TPM2_ECC_{attr}" emap[ev] = en for e in val: ename = emap[e] d[ename] = int(e) return d def encode_tpml_handle(self, val: TPML_HANDLE) -> List[int]: handles = list() for h in val: hs = int(h) handles.append(hs) return handles def encode_tpml_alg_property(self, val: TPML_ALG_PROPERTY) -> Dict[str, Dict]: d = dict() for v in val: ev = self.encode(v) d.update(ev) return d def encode_tpml_cca(self, val: TPML_CCA) -> Dict[str, Dict]: d = dict() for v in val: ev = self.encode(v) d.update(ev) return d def encode_tpml_digest_values(self, val: TPML_DIGEST_VALUES) -> Dict[str, str]: d = dict() for v in val: an = str(v.hashAlg) if an == "sha": an = "sha1" d[an] = hexlify(bytes(v)).decode("ascii") return d def encode_tpml_alg(self, val: TPML_ALG) -> Dict[str, str]: algs = list() for v in val: an = str(v) if an == "sha": an = "sha1" algs.append(an) return {"remaining": " ".join(algs)} def encode_tpml( self, val: Union[ TPML_PCR_SELECTION, TPML_TAGGED_TPM_PROPERTY, TPML_ECC_CURVE, TPML_HANDLE, TPML_ALG_PROPERTY, TPML_CCA, TPML_DIGEST_VALUES, TPML_ALG, ], ) -> Any: t = type(val) if isinstance(val, TPML_PCR_SELECTION): return self.encode_tpml_pcr_selection(val) elif isinstance(val, TPML_TAGGED_TPM_PROPERTY): return self.encode_tpml_tagged_tpm_property(val) elif isinstance(val, TPML_ECC_CURVE): return self.encode_tpml_ecc_curve(val) elif isinstance(val, TPML_HANDLE): return self.encode_tpml_handle(val) elif isinstance(val, TPML_ALG_PROPERTY): return self.encode_tpml_alg_property(val) elif isinstance(val, TPML_CCA): return self.encode_tpml_cca(val) elif isinstance(val, TPML_DIGEST_VALUES): return self.encode_tpml_digest_values(val) elif isinstance(val, TPML_ALG): return self.encode_tpml_alg(val) raise ValueError(f"unsupported list {t.__name__}") def encode_struct( self, val: Union[ TPMS_NV_PUBLIC, TPMT_PUBLIC, TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT, TPMS_ALG_PROPERTY, TPMS_PCR_SELECTION, TPMS_TAGGED_PROPERTY, TPMS_CLOCK_INFO, TPMS_CONTEXT, ], ) -> Dict[str, Any]: t = type(val) if isinstance(val, TPMS_NV_PUBLIC): return self.encode_tpms_nv_public(val) elif isinstance(val, TPMT_PUBLIC): return self.encode_tpmt_public(val) elif isinstance(val, (TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT)): return self.encode_tpmt_sym_def(val) elif isinstance(val, TPMS_ALG_PROPERTY): return self.encode_tpms_alg_property(val) elif isinstance(val, TPMS_PCR_SELECTION): return self.encode_tpms_pcr_selection(val) elif isinstance(val, TPMS_TAGGED_PROPERTY): return self.encode_tpms_tagged_property(val) elif isinstance(val, TPMS_CLOCK_INFO): return self.encode_tpms_clock_info(val) elif isinstance(val, TPMS_CONTEXT): return self.encode_tpms_context(val) elif isinstance(val, TPMS_NV_PIN_COUNTER_PARAMETERS): return self.encode_tpms_nv_pin_counter_parameters(val) raise ValueError(f"unsupported structure {t.__name__}") def decode_int(self, dst: int, src: Union[Dict[str, Any], int]) -> int: if isinstance(src, dict) and "counter" in src: return src.get("counter") elif isinstance(src, dict) and "bits" in src: v = 0 for i in src["bits"]: v = v | (1 << i) return v return super().decode_int(dst, src) def decode_friendly_int( self, dst: TPM_FRIENDLY_INT, src: Dict[str, Union[int, str]] ) -> TPM_FRIENDLY_INT: if "friendly" in src and "value" in src: raw = src.get("value") else: raw = src.get("raw") return dst.__class__(raw) def decode_tpma_cc(self, src: Dict[str, Dict]) -> TPMA_CC: _, v = src.popitem() val = v.get("value") return TPMA_CC(val) def decode_tpma_permanent(self, src: Dict[str, int]) -> TPMA_PERMANENT: rv = TPMA_PERMANENT() if src.get("ownerAuthSet"): rv = rv | TPMA_PERMANENT.OWNERAUTHSET if src.get("endorsementAuthSet"): rv = rv | TPMA_PERMANENT.ENDORSEMENTAUTHSET if src.get("lockoutAuthSet"): rv = rv | TPMA_PERMANENT.LOCKOUTAUTHSET if src.get("disableClear"): rv = rv | TPMA_PERMANENT.DISABLECLEAR if src.get("inLockout"): rv = rv | TPMA_PERMANENT.INLOCKOUT if src.get("tpmGeneratedEPS"): rv = rv | TPMA_PERMANENT.TPMGENERATEDEPS return rv def decode_tpma_startup(self, src: Dict[str, int]) -> TPMA_STARTUP: rv = TPMA_STARTUP() if src.get("phEnable"): rv |= TPMA_STARTUP.CLEAR_PHENABLE if src.get("shEnable"): rv |= TPMA_STARTUP.CLEAR_SHENABLE if src.get("ehEnable"): rv |= TPMA_STARTUP.CLEAR_EHENABLE if src.get("phEnableNV"): rv |= TPMA_STARTUP.CLEAR_PHENABLENV if src.get("orderly"): rv |= TPMA_STARTUP.CLEAR_ORDERLY return rv def decode_tpma_session(self, src: Dict[str, str]) -> TPMA_SESSION: astr = src.get("Session-Attributes") return TPMA_SESSION.parse(astr) def decode_friendly_intlist( self, dst: TPMA_FRIENDLY_INTLIST, src: Dict[str, Any] ) -> TPMA_FRIENDLY_INTLIST: if isinstance(dst, TPMA_CC): return self.decode_tpma_cc(src) elif isinstance(dst, TPMA_PERMANENT): return self.decode_tpma_permanent(src) elif isinstance(dst, TPMA_STARTUP): return self.decode_tpma_startup(src) elif isinstance(dst, TPMA_SESSION): return self.decode_tpma_session(src) if "friendly" in src and "value" in src: raw = src.get("value") else: raw = src.get("raw") return dst.__class__(raw) def decode_tpml_pcr_selection( self, dst: TPML_PCR_SELECTION, src: Dict[str, List] ) -> TPML_PCR_SELECTION: l = src.get("selected-pcrs") i = 0 for e in l: s = self.decode(TPMS_PCR_SELECTION(), e) dst[i] = s i += 1 return dst def decode_tpml_tagged_tpm_property( self, dst: TPML_TAGGED_TPM_PROPERTY, src: Dict[str, Any] ) -> TPML_TAGGED_TPM_PROPERTY: i = 0 for k, v in src.items(): tp = TPMS_TAGGED_PROPERTY() self.decode(tp, {k: v}) dst[i] = tp i += 1 return dst def decode_tpml_ecc_curve( self, dst: TPML_ECC_CURVE, src: Dict[str, int] ) -> TPML_ECC_CURVE: i = 0 for k, v in src.items(): dst[i] = TPM2_ECC(v) i += 1 return dst def decode_tpml_handle(self, dst: TPML_HANDLE, src: List[int]) -> TPML_HANDLE: i = 0 for h in src: dst[i] = TPM2_HANDLE(h) i += 1 return dst def decode_tpml_alg_property( self, dst: TPML_ALG_PROPERTY, src: Dict[str, Dict] ) -> TPML_ALG_PROPERTY: i = 0 for k, v in src.items(): dst[i] = self.decode(TPMS_ALG_PROPERTY(), {k: v}) i += 1 return dst def decode_tpml_cca(self, dst: TPML_CCA, src: Dict[str, Dict]) -> TPML_CCA: i = 0 for k, v in src.items(): dst[i] = self.decode(TPMA_CC(), {k: v}) i += 1 return dst def decode_tpml_digest_values( self, dst: TPML_DIGEST_VALUES, src: Dict[str, str] ) -> TPML_DIGEST_VALUES: digs = list() for an, dh in src.items(): alg = TPM2_ALG.parse(an) dig = unhexlify(dh) digs.append(TPMT_HA(hashAlg=alg, digest=TPMU_HA(sha512=dig))) return TPML_DIGEST_VALUES(digs) def decode_tpml_alg(self, dst: TPML_ALG, src: Dict[str, str]) -> TPML_ALG: algstr = src.get("remaining", "") algs = algstr.split() return TPML_ALG([TPM2_ALG.parse(x) for x in algs]) def decode_tpml( self, dst: Union[ TPML_PCR_SELECTION, TPML_TAGGED_TPM_PROPERTY, TPML_ECC_CURVE, TPML_HANDLE, TPML_ALG_PROPERTY, TPML_CCA, TPML_DIGEST_VALUES, TPML_ALG, ], src: Union[Dict, List], ) -> Union[ TPML_PCR_SELECTION, TPML_TAGGED_TPM_PROPERTY, TPML_ECC_CURVE, TPML_HANDLE, TPML_ALG_PROPERTY, TPML_CCA, TPML_DIGEST_VALUES, TPML_ALG, ]: t = type(dst) if isinstance(dst, TPML_PCR_SELECTION): return self.decode_tpml_pcr_selection(dst, src) elif isinstance(dst, TPML_TAGGED_TPM_PROPERTY): return self.decode_tpml_tagged_tpm_property(dst, src) elif isinstance(dst, TPML_ECC_CURVE): return self.decode_tpml_ecc_curve(dst, src) elif isinstance(dst, TPML_HANDLE): return self.decode_tpml_handle(dst, src) elif isinstance(dst, TPML_ALG_PROPERTY): return self.decode_tpml_alg_property(dst, src) elif isinstance(dst, TPML_CCA): return self.decode_tpml_cca(dst, src) elif isinstance(dst, TPML_DIGEST_VALUES): return self.decode_tpml_digest_values(dst, src) elif isinstance(dst, TPML_ALG): return self.decode_tpml_alg(dst, src) raise ValueError(f"unsupported list {t.__name__}") def decode_tpms_nv_public( self, dst: TPMS_NV_PUBLIC, src: Dict[str, Dict] ) -> TPMS_NV_PUBLIC: k, v = src.popitem() dst.nvIndex = k dst.nameAlg = self.decode(TPM2_ALG(), v.get("hash algorithm")) dst.attributes = self.decode(TPMA_NV(), v.get("attributes")) dst.dataSize = v["size"] dst.authPolicy = self.decode(TPM2B_DIGEST(), v.get("authorization policy", b"")) return dst def decode_tpmt_public(self, dst: TPMT_PUBLIC, src: Dict) -> TPMT_PUBLIC: dst.nameAlg = self.decode(TPM2_ALG(), src["name-alg"]) dst.objectAttributes = self.decode(TPMA_OBJECT(), src["attributes"]) dst.type = self.decode(TPM2_ALG(), src["type"]) if dst.type == TPM2_ALG.RSA: e = src["exponent"] dst.parameters.rsaDetail.exponent = 0 if e == 65537 else e dst.parameters.rsaDetail.keyBits = src["bits"] dst.parameters.rsaDetail.scheme.scheme = self.decode( TPM2_ALG(), src["scheme"] ) if dst.parameters.rsaDetail.scheme.scheme != TPM2_ALG.RSAES: dst.parameters.rsaDetail.scheme.details.anySig.hashAlg = self.decode( TPM2_ALG(), src["scheme-halg"] ) dst.parameters.rsaDetail.symmetric = self.decode(TPMT_SYM_DEF_OBJECT(), src) dst.unique.rsa = unhexlify(src["rsa"]) elif dst.type == TPM2_ALG.ECC: dst.parameters.eccDetail.curveID = self.decode(TPM2_ECC(), src["curve-id"]) dst.parameters.eccDetail.kdf.scheme = self.decode( TPM2_ALG(), src["kdfa-alg"] ) dst.parameters.eccDetail.kdf.details.mgf1.hashAlg = self.decode( TPM2_ALG(), src["kdfa-halg"] ) dst.parameters.eccDetail.scheme.scheme = self.decode( TPM2_ALG(), src["scheme"] ) dst.parameters.eccDetail.scheme.details.anySig.hashAlg = self.decode( TPM2_ALG(), src["scheme-halg"] ) if dst.parameters.eccDetail.scheme.scheme == TPM2_ALG.ECDAA: dst.parameters.eccDetail.scheme.details.ecdaa.count dst.parameters.eccDetail.symmetric = self.decode(TPMT_SYM_DEF_OBJECT(), src) dst.unique.ecc.x = unhexlify(src["x"]) dst.unique.ecc.y = unhexlify(src["y"]) elif dst.type == TPM2_ALG.KEYEDHASH: dst.parameters.keyedHashDetail.scheme.scheme = self.decode( TPM2_ALG(), src["algorithm"] ) dst.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = self.decode( TPM2_ALG(), src["hash-alg"] ) if dst.parameters.keyedHashDetail.scheme.scheme == TPM2_ALG.XOR: dst.parameters.keyedHashDetail.scheme.details.exclusiveOr.kdf = self.decode( TPM2_ALG(), src["kdfa-alg"] ) dst.unique.keyedHash = unhexlify(src["keyedhash"]) elif dst.type == TPM2_ALG.SYMCIPHER: dst.parameters.symDetail.sym = self.decode(TPMT_SYM_DEF_OBJECT(), src) dst.unique.sym = unhexlify(src["symcipher"]) return dst def decode_tpmt_sym_def( self, dst: Union[TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT], src: Dict[str, Any] ) -> Union[TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT]: dst.algorithm = self.decode(TPM2_ALG(), src["sym-alg"]) dst.mode.sym = self.decode(TPM2_ALG(), src["sym-mode"]) dst.keyBits.sym = src["sym-keybits"] return dst def decode_tpms_alg_property( self, dst: TPMS_ALG_PROPERTY, src: Dict[str, Dict] ) -> TPMS_ALG_PROPERTY: _, d = src.popitem() dst.alg = TPM2_ALG(d["value"]) if d.get("asymmetric"): dst.algProperties |= TPMA_ALGORITHM.ASYMMETRIC if d.get("symmetric"): dst.algProperties |= TPMA_ALGORITHM.SYMMETRIC if d.get("hash"): dst.algProperties |= TPMA_ALGORITHM.HASH if d.get("object"): dst.algProperties |= TPMA_ALGORITHM.OBJECT if d.get("reserved"): res = d["reserved"] << 4 dst.algProperties |= TPMA_ALGORITHM.RESERVED1_MASK & res if d.get("signing"): dst.algProperties |= TPMA_ALGORITHM.SIGNING if d.get("encrypting"): dst.algProperties |= TPMA_ALGORITHM.ENCRYPTING if d.get("method"): dst.algProperties |= TPMA_ALGORITHM.METHOD return dst def decode_tpms_pcr_selection( self, dst: TPMS_PCR_SELECTION, src: Dict[str, Dict] ) -> TPMS_PCR_SELECTION: k, v = src.popitem() dst.hash = TPM2_ALG.parse(k) pi = 0 for p in v: pi |= 1 << p pb = bytes(reversed(pi.to_bytes(4, "big"))).rstrip(b"\x00") dst.sizeofSelect = len(pb) dst.pcrSelect = pb return dst def decode_tpms_tagged_property( self, dst: TPMS_TAGGED_PROPERTY, src: Dict[str, Any] ) -> TPMS_TAGGED_PROPERTY: pmap = dict([(v, k) for k, v in self._build_pt_map().items()]) ps, v = src.popitem() dst.property = pmap[ps] if dst.property == TPM2_PT.PERMANENT: dst.value = self.decode(TPMA_PERMANENT(), v) elif dst.property == TPM2_PT.STARTUP_CLEAR: dst.value = self.decode(TPMA_STARTUP(), v) elif isinstance(v, int): dst.value = v elif isinstance(v, dict): dst.value = v.get("raw") def decode_tpms_clock_info( self, dst: TPMS_CLOCK_INFO, src: Dict[str, int] ) -> TPMS_CLOCK_INFO: dst.clock = src["clock"] dst.resetCount = src["resetCount"] dst.restartCount = src["restartCount"] dst.safe = src["safe"] return dst def decode_struct( self, dst: Union[ TPMS_NV_PUBLIC, TPMT_PUBLIC, TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT, TPMS_ALG_PROPERTY, TPMS_PCR_SELECTION, TPMS_TAGGED_PROPERTY, TPMS_CLOCK_INFO, ], src: Dict[str, Any], ) -> Union[ TPMS_NV_PUBLIC, TPMT_PUBLIC, TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT, TPMS_ALG_PROPERTY, TPMS_PCR_SELECTION, TPMS_TAGGED_PROPERTY, TPMS_CLOCK_INFO, ]: t = type(dst) if isinstance(dst, TPMS_NV_PUBLIC): return self.decode_tpms_nv_public(dst, src) elif isinstance(dst, TPMT_PUBLIC): return self.decode_tpmt_public(dst, src) elif isinstance(dst, (TPMT_SYM_DEF, TPMT_SYM_DEF_OBJECT)): return self.decode_tpmt_sym_def(dst, src) elif isinstance(dst, TPMS_ALG_PROPERTY): return self.decode_tpms_alg_property(dst, src) elif isinstance(dst, TPMS_PCR_SELECTION): return self.decode_tpms_pcr_selection(dst, src) elif isinstance(dst, TPMS_TAGGED_PROPERTY): return self.decode_tpms_tagged_property(dst, src) elif isinstance(dst, TPMS_CLOCK_INFO): return self.decode_tpms_clock_info(dst, src) raise ValueError(f"unsupported structure {t.__name__}") def _is_pcr_tuple(self, val): return ( isinstance(val, tuple) and len(val) == 2 and isinstance(val[0], TPML_PCR_SELECTION) and isinstance(val[1], TPML_DIGEST) ) def _is_pcr_tuples(self, val): if not val or not isinstance(val, collections.abc.Iterable): return False for v in val: if not self._is_pcr_tuple(v): return False return True def encode_pcr_tuple( self, val: Tuple[TPML_PCR_SELECTION, TPML_DIGEST] ) -> Dict[str, List]: d = dict() sels, digs = val di = 0 for s in sels: bn = str(s.hash) if bn == "sha": bn = "sha1" if d.get(bn) is None: d[bn] = dict() rb = bytes(reversed(bytes(s.pcrSelect))) pi = int.from_bytes(rb, "big") for i in range(0, s.sizeofSelect * 8): if 1 << i & pi: d[bn][i] = int.from_bytes(digs[di], "big") di += 1 return d def encode_pcr_tuples( self, val: List[Tuple[TPML_PCR_SELECTION, TPML_DIGEST]] ) -> Dict[str, List]: d = dict() for v in val: pv = self.encode(v) for bank, digs in pv.items(): if d.get(bank) is None: d[bank] = dict() d[bank].update(digs) return d def encode_name(self, val: TPM2B_NAME) -> Dict[str, str]: return {"name": hexlify(val.name).decode("ascii")} def encode(self, val): if self._is_pcr_tuple(val): return self.encode_pcr_tuple(val) elif self._is_pcr_tuples(val): return self.encode_pcr_tuples(val) elif isinstance(val, TPM2B_NAME): return self.encode_name(val) return super().encode(val) def decode_pcr_tuples( self, dst: Tuple[TPML_PCR_SELECTION, TPML_DIGEST], src: Dict[str, Dict[int, str]], ) -> List[Tuple[TPML_PCR_SELECTION, TPML_DIGEST]]: pcrdigs = list() for bank, pcrs in src.items(): bankalg = TPM2_ALG.parse(bank) digsize = _get_digest_size(bankalg) for pcr, di in pcrs.items(): dig = di.to_bytes(digsize, "big") pcrdigs.append((bankalg, pcr, dig)) rl = list() sels = list() digs = list() sel = TPMS_PCR_SELECTION(hash=pcrdigs[0][0]) for bank, pcr, dig in pcrdigs: if bank != sel.hash: sels.append(sel) sel = TPMS_PCR_SELECTION(hash=bank) sel.pcrSelect[pcr // 8] |= 1 << (pcr % 8) sel.sizeofSelect = len(bytes(sel.pcrSelect).rstrip(b"\x00")) digs.append(dig) if len(digs) == 8: sels.append(sel) sel = TPMS_PCR_SELECTION(hash=bank) sl = TPML_PCR_SELECTION(sels) dl = TPML_DIGEST(digs) rl.append((sl, dl)) sels = list() digs = list() if len(digs): sels.append(sel) sl = TPML_PCR_SELECTION(sels) dl = TPML_DIGEST(digs) rl.append((sl, dl)) return rl def decode_name(self, dst: TPM2B_NAME, src: Dict[str, str]) -> TPM2B_NAME: if "loaded-key" in src: src = src["loaded-key"] name = unhexlify(src["name"]) name2b = TPM2B_NAME(name=name) return name2b def decode_tpmt_ha(self, dst: TPMT_HA, src: Dict[str, str]) -> TPMT_HA: k, v = src.popitem() alg = TPM2_ALG.parse(k) ds = _get_digest_size(alg) dig = v.to_bytes(ds, "big") dst.hashAlg = alg dst.digest.sha512 = dig return dst def decode_tpms_nv_pin_counter_parameters( self, dst: TPMS_NV_PIN_COUNTER_PARAMETERS, src: Dict[str, Union[Dict, int]] ) -> TPMS_NV_PIN_COUNTER_PARAMETERS: print(src) if "pinfail" in src: src = src["pinfail"] elif "pinpass" in src: src = src["pinpass"] dst.pinCount = src["pinCount"] dst.pinLimit = src["pinLimit"] return dst def decode(self, dst, src): if self._is_pcr_tuple(dst): return self.decode_pcr_tuples(dst, src) elif isinstance(dst, TPM2B_NAME): return self.decode_name(dst, src) elif isinstance(dst, TPMT_HA): return self.decode_tpmt_ha(dst, src) elif isinstance(dst, TPMS_NV_PIN_COUNTER_PARAMETERS): return self.decode_tpms_nv_pin_counter_parameters(dst, src) return super().decode(dst, src) def to_yaml(val: TPM_OBJECT) -> str: enc = tools_encdec() ev = enc.encode(val) return yaml.safe_dump(ev, sort_keys=False) def from_yaml(src, dst): dec = tools_encdec() d = yaml.safe_load(src) return dec.decode(dst, d) tpm2-pytss-2.3.0/src/tpm2_pytss/fapi_info.py000066400000000000000000000127711463722220500210100ustar00rootroot00000000000000# 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-2.3.0/src/tpm2_pytss/internal/000077500000000000000000000000001463722220500203105ustar00rootroot00000000000000tpm2-pytss-2.3.0/src/tpm2_pytss/internal/__init__.py000066400000000000000000000000001463722220500224070ustar00rootroot00000000000000tpm2-pytss-2.3.0/src/tpm2_pytss/internal/crypto.py000066400000000000000000000557171463722220500222210ustar00rootroot00000000000000# 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 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 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 import sys _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), ) if hasattr(hashes, "SM3"): _digesttable += ((TPM2_ALG.SM3_256, hashes.SM3),) _algtable = ( (TPM2_ALG.AES, AES), (TPM2_ALG.CAMELLIA, Camellia), (TPM2_ALG.CFB, modes.CFB), ) try: from cryptography.hazmat.primitives.ciphers.algorithms import SM4 _algtable += ((TPM2_ALG.SM4, SM4),) except ImportError: # SM4 not implemented by cryptography package, ignore, no SM4 support. pass 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): 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}") sig = bytes(signature.signature.rsapss.sig) try: key.verify(sig, data, pad, dt()) except InvalidSignature: if mpad: key.verify(sig, data, mpad, dt()) else: raise def verify_signature_ecc(signature, key, data): dt = _get_digest(signature.signature.any.hashAlg) if dt is None: raise ValueError( f"unsupported digest algorithm: {signature.signature.ecdsa.hash}" ) 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(dt())) def verify_signature_hmac(signature, key, data): dt = _get_digest(signature.signature.hmac.hashAlg) if dt is None: raise ValueError( f"unsupported digest algorithm: {signature.signature.hmac.hashAlg}" ) 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): 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) 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) 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) 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 = int(key.curve.key_size / 8) # FIXME ceiling here 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 elif hasattr(decrypt_padding, "_algorithm"): # This is an ugly hack, but until cryptography 42 is released it's needed. alg = type(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-2.3.0/src/tpm2_pytss/internal/templates.py000066400000000000000000000173721463722220500226720ustar00rootroot00000000000000from collections import namedtuple 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, ) from ..constants import ( TPM2_ALG, TPMA_OBJECT, TPM2_ECC, ) class _ek: _ek_tuple = namedtuple("_ek_tuple", ["cert_index", "ek_template"]) _low_symmetric = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) _low_attrs = ( TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.ADMINWITHPOLICY | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT ) _low_policy = b"\x83q\x97gD\x84\xb3\xf8\x1a\x90\xcc\x8dF\xa5\xd7$\xfdR\xd7n\x06R\x0bd\xf2\xa1\xda\x1b3\x14i\xaa" _ek_rsa2048_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=_low_attrs, authPolicy=_low_policy, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=_low_symmetric, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=2048, ), ), unique=TPMU_PUBLIC_ID(rsa=b"\x00" * 256), ) ) _ek_ecc256_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=_low_attrs, authPolicy=_low_policy, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=_low_symmetric, 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)), ) ) _high_attrs = ( TPMA_OBJECT.FIXEDTPM | TPMA_OBJECT.FIXEDPARENT | TPMA_OBJECT.SENSITIVEDATAORIGIN | TPMA_OBJECT.USERWITHAUTH | TPMA_OBJECT.ADMINWITHPOLICY | TPMA_OBJECT.RESTRICTED | TPMA_OBJECT.DECRYPT ) _256_symmetric = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.AES, keyBits=TPMU_SYM_KEY_BITS(aes=256), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) _sm4_symmetric = TPMT_SYM_DEF_OBJECT( algorithm=TPM2_ALG.SM4, keyBits=TPMU_SYM_KEY_BITS(sm4=128), mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), ) _sha256_policy = 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_policy = 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_policy = 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_policy = b"\x16x`\xa3_,\\5g\xf9\xc9'\xacV\xc02\xf3\xb3\xa6F/\x8d\x03y\x98\xe7\xa1\x0fw\xfaEJ" _ek_high_rsa2048_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA256, objectAttributes=_high_attrs, authPolicy=_sha256_policy, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=_low_symmetric, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=2048, ), ), ) ) _ek_high_ecc256_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA256, objectAttributes=_high_attrs, authPolicy=_sha256_policy, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=_low_symmetric, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) _ek_high_ecc384_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA384, objectAttributes=_high_attrs, authPolicy=_sha384_policy, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=_256_symmetric, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P384, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) _ek_high_ecc521_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SHA512, objectAttributes=_high_attrs, authPolicy=_sha512_policy, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=_256_symmetric, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.NIST_P521, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) _ek_high_eccsm2p521_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.ECC, nameAlg=TPM2_ALG.SM3_256, objectAttributes=_high_attrs, authPolicy=_sm3_256_policy, parameters=TPMU_PUBLIC_PARMS( eccDetail=TPMS_ECC_PARMS( symmetric=_sm4_symmetric, scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), curveID=TPM2_ECC.SM2_P256, kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), ), ), ), ) _ek_high_rsa3072_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA384, objectAttributes=_high_attrs, authPolicy=_sha384_policy, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=_256_symmetric, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=3072, ), ), ) ) _ek_high_rsa4096_template = TPM2B_PUBLIC( publicArea=TPMT_PUBLIC( type=TPM2_ALG.RSA, nameAlg=TPM2_ALG.SHA384, objectAttributes=_high_attrs, authPolicy=_sha384_policy, parameters=TPMU_PUBLIC_PARMS( rsaDetail=TPMS_RSA_PARMS( symmetric=_256_symmetric, scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), keyBits=3072, ), ), ) ) EK_RSA2048 = _ek_tuple(0x01C00002, _ek_rsa2048_template) EK_ECC256 = _ek_tuple(0x01C0000A, _ek_ecc256_template) EK_HIGH_RSA2048 = _ek_tuple(0x01C00012, _ek_high_rsa2048_template) EK_HIGH_ECC256 = _ek_tuple(0x01C00014, _ek_high_ecc256_template) EK_HIGH_ECC384 = _ek_tuple(0x01C00016, _ek_high_ecc384_template) EK_HIGH_ECC521 = _ek_tuple(0x01C00018, _ek_high_ecc521_template) EK_HIGH_ECCSM2P521 = _ek_tuple(0x01C0001A, _ek_high_eccsm2p521_template) EK_HIGH_RSA3072 = _ek_tuple(0x01C0001C, _ek_high_rsa3072_template) EK_HIGH_RSA4096 = _ek_tuple(0x01C0001E, _ek_high_rsa4096_template) tpm2-pytss-2.3.0/src/tpm2_pytss/internal/utils.py000066400000000000000000000275071463722220500220350ustar00rootroot00000000000000# 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 __lte__(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 clazz.contains(friendly): 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-2.3.0/src/tpm2_pytss/policy.py000066400000000000000000000466171463722220500203630ustar00rootroot00000000000000# 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-2.3.0/src/tpm2_pytss/tsskey.py000066400000000000000000000264151463722220500204000ustar00rootroot00000000000000# 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) 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) 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-2.3.0/src/tpm2_pytss/types.py000066400000000000000000002150341463722220500202170ustar00rootroot00000000000000# 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, ) 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): """"A handle to a TPM address""" pass class TPM_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_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_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) 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] 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_PUBLIC_PARMS(TPM_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(TPM_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(TPM_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( f"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(TPM_OBJECT): pass class TPMU_KDF_SCHEME(TPM_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(TPM_OBJECT): pass class TPMU_SYM_MODE(TPM_OBJECT): pass class TPM2B_AUTH(TPM2B_SIMPLE_OBJECT): pass class TPM2B_NONCE(TPM2B_SIMPLE_OBJECT): pass class TPMU_PUBLIC_ID(TPM_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(TPM_OBJECT): pass class TPMU_SCHEME_KEYEDHASH(TPM_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(TPM_OBJECT): pass class TPMT_SIG_SCHEME(TPM_OBJECT): pass class TPMU_SIGNATURE(TPM_OBJECT): pass class TPMT_SIGNATURE(TPM_OBJECT): def verify_signature(self, key, data): """ 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. Raises: :py:class:`cryptography.exceptions.InvalidSignature`: when the signature doesn't match the data. """ _verify_signature(self, key, data) 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(TPM_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 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-2.3.0/src/tpm2_pytss/utils.py000066400000000000000000000420711463722220500202120ustar00rootroot00000000000000from .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 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( 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( 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. """ en = ektype.replace("-", "_") if not hasattr(_ek, en): raise ValueError(f"unknown EK type {ektype}") (cert_index, template) = getattr(_ek, en) nonce_index = None if ektype in ("EK-RSA2048", "EK-ECC256"): nonce_index = cert_index + 1 template_index = cert_index + 2 else: template_index = cert_index + 1 cert = None try: cert = nv_read_cb(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) 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 nonce_index: try: nonce = nv_read_cb(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 template.publicArea.type == TPM2_ALG.RSA: template.publicArea.unique.rsa = nonce + ((256 - len(nonce)) * b"\x00") elif ( nonce and template.publicArea.type == TPM2_ALG.ECC and template.publicArea.parameters.eccDetail.curveID == TPM2_ECC.NIST_P256 ): template.publicArea.unique.ecc.x = nonce + ((32 - len(nonce)) * b"\x00") template.publicArea.unique.ecc.y = b"\x00" * 32 return cert, 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-2.3.0/test/000077500000000000000000000000001463722220500145405ustar00rootroot00000000000000tpm2-pytss-2.3.0/test/TSS2_BaseTest.py000066400000000000000000000126521463722220500174450ustar00rootroot00000000000000# 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): self._port = None 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): self._port = None 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 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] def tearDown(self): self.ectx.close() self.tcti.close() super().tearDown() tpm2-pytss-2.3.0/test/__init__.py000066400000000000000000000000001463722220500166370ustar00rootroot00000000000000tpm2-pytss-2.3.0/test/test_crypto.py000066400000000000000000001110101463722220500174630ustar00rootroot00000000000000#!/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.assertIn( str(e.exception), ( "unsupported key type: _DSAPrivateKey", "unsupported key type: DSAPrivateKey", ), ) with self.assertRaises(ValueError) as e: TPMT_PUBLIC.from_pem(dsa_public_key) self.assertIn( str(e.exception), ( "unsupported key type: _DSAPublicKey", "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), TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL), ) crypto._verify_signature(sig, secret, msg) 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), TPMT_TK_HASHCHECK(tag=TPM2_ST.HASHCHECK, hierarchy=TPM2_RH.NULL), ) crypto._verify_signature(sig, public, msg) def test_verify_singature_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) 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) 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) 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) 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) 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-2.3.0/test/test_cryptography.py000066400000000000000000000464311463722220500207140ustar00rootroot00000000000000#!/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 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.SECP192R1()) 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 secp192r1, 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) tpm2-pytss-2.3.0/test/test_encoding.py000066400000000000000000001651411463722220500177470ustar00rootroot00000000000000#!/usr/bin/python3 -u """ SPDX-License-Identifier: BSD-2 """ import unittest from tpm2_pytss import * from tpm2_pytss.encoding import ( base_encdec, json_encdec, tools_encdec, to_yaml, from_yaml, ) from tpm2_pytss.internal.utils import TSS2Version from binascii import unhexlify, hexlify from .TSS2_BaseTest import TSS2_BaseTest import shutil from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import serialization import subprocess import sys import os 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") class ToolsTest(TSS2_BaseTest): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.has_tools = False if shutil.which("tpm2") and sys.version_info >= (3, 7): self.has_tools = True self.tools_version = self._get_tools_version() def run_tool(self, *tool_args, no_tcti=False): args = ("tpm2",) + tuple(tool_args) if not no_tcti: tcti = self.tpm.tcti_name_conf args = args + ("--tcti", tcti) su_args = ("tpm2", "startup", "--clear", "--tcti", tcti) res = subprocess.run(su_args, timeout=20, capture_output=True, text=True) if res.returncode != 0: raise RuntimeError( f"tpm2 startup failed with {res.returncode}: {res.stderr}" ) res = subprocess.run(args, timeout=20, capture_output=True, text=True) if res.returncode != 0: raise RuntimeError( f"{' '.join(args)} failed with {res.returncode}: {res.stderr}" ) return res.stdout def _get_tools_version(self): out = self.run_tool("--version", no_tcti=True) kvps = out.split() kvp = [x for x in kvps if "version=" in x][0] return TSS2Version(kvp.split("=")[1].replace('"', "")) def test_tools_tpms_nv_public(self): self.maxDiff = None enc = tools_encdec() nvp = TPMS_NV_PUBLIC( nvIndex=0xFABC1234, nameAlg=TPM2_ALG.SHA1, attributes=TPMA_NV.POLICYWRITE | TPMA_NV.AUTHREAD, authPolicy=b"\x0a\x0b\x0c\x0d\x01\x02\x03\x04", dataSize=3, ) ev = enc.encode(nvp) self.assertEqual( ev, { 0xFABC1234: { "name": "00047bbf13f835329dc6e1fedabc11f25a0cc3656ebc", "hash algorithm": {"friendly": "sha1", "value": 0x4}, "attributes": { "friendly": "policywrite|authread", "value": 0x40008, }, "size": 3, "authorization policy": "0A0B0C0D01020304", }, }, ) def test_tools_tpmt_public(self): self.maxDiff = None enc = tools_encdec() _, sympub = TPM2B_SENSITIVE.symcipher_from_secret( b"\xFA" * 32, seed=b"\x00" * 32 ) ev = enc.encode(sympub) self.assertEqual( ev, { "name-alg": {"value": "sha256", "raw": 0xB}, "attributes": {"value": "userwithauth|decrypt|sign", "raw": 0x60040}, "type": {"value": "symcipher", "raw": 0x25}, "sym-alg": {"value": "aes", "raw": 0x6}, "sym-mode": {"value": "cfb", "raw": 0x43}, "sym-keybits": 256, "symcipher": "69fa9a376a9798e756d36172120be93b464ebaf76d200ab7502f9ec53a73182f", }, ) keyedscheme = TPMT_KEYEDHASH_SCHEME( scheme=TPM2_ALG.HMAC, details=TPMU_SCHEME_KEYEDHASH( hmac=TPMS_SCHEME_HASH(hashAlg=TPM2_ALG.SHA512), ), ) _, keyedpub = TPM2B_SENSITIVE.keyedhash_from_secret( b"\xFA" * 32, scheme=keyedscheme, seed=b"\x00" * 32 ) ev = enc.encode(keyedpub) self.assertEqual( ev, { "name-alg": {"value": "sha256", "raw": 0xB}, "attributes": {"value": "userwithauth|decrypt|sign", "raw": 0x60040}, "type": {"value": "keyedhash", "raw": 0x8}, "hash-alg": {"value": "sha512", "raw": 0xD}, }, ) rsapub = TPM2B_PUBLIC.parse( "rsa2048:rsapss-sha256", authPolicy=b"\x0a\x0b\x0c\x0d", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ^ TPMA_OBJECT.DECRYPT, ) rsapub.publicArea.unique.rsa = b"\xFF" * 256 ev = enc.encode(rsapub) self.assertEqual( ev, { "name-alg": {"value": "sha256", "raw": 0xB}, "attributes": { "value": "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign", "raw": 0x40072, }, "type": {"value": "rsa", "raw": 0x1}, "exponent": 65537, "bits": 2048, "scheme": {"value": "rsapss", "raw": 0x16}, "scheme-halg": {"value": "sha256", "raw": 0xB}, "sym-alg": {"value": "aes", "raw": 0x6}, "sym-mode": {"value": "cfb", "raw": 0x43}, "sym-keybits": 128, "rsa": "ff" * 256, "authorization policy": "0a0b0c0d", }, ) eccpub = TPM2B_PUBLIC.parse( "ecc:ecdh:aes256cfb", objectAttributes=TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS ^ TPMA_OBJECT.DECRYPT, ) eccpub.publicArea.unique.ecc.x = b"x" * 32 eccpub.publicArea.unique.ecc.y = b"y" * 32 ev = enc.encode(eccpub) self.assertEqual( ev, { "name-alg": {"value": "sha256", "raw": 0xB}, "attributes": { "value": "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign", "raw": 0x40072, }, "type": {"value": "ecc", "raw": 0x23}, "curve-id": {"value": "nist_p256", "raw": 0x3}, "kdfa-alg": {"value": None, "raw": 0x10}, "kdfa-halg": {"value": "error", "raw": 0x0}, "scheme": {"value": "ecdh", "raw": 0x19}, "scheme-halg": {"value": "sha256", "raw": 0xB}, "sym-alg": {"value": "aes", "raw": 0x6}, "sym-mode": {"value": "cfb", "raw": 0x43}, "sym-keybits": 256, "x": "78" * 32, "y": "79" * 32, }, ) def test_tools_tpml_alg_property(self): enc = tools_encdec() al = TPML_ALG_PROPERTY( [ TPMS_ALG_PROPERTY( alg=TPM2_ALG.RSA, algProperties=(TPMA_ALGORITHM.RESERVED1_MASK & 0xA << 4) | TPMA_ALGORITHM.ASYMMETRIC | TPMA_ALGORITHM.OBJECT, ), ] ) ev = enc.encode(al) self.assertEqual( ev, { "rsa": { "value": 0x1, "asymmetric": 1, "symmetric": 0, "hash": 0, "object": 1, "reserved": 0xA, "signing": 0, "encrypting": 0, "method": 0, }, }, ) def test_tools_tpml_cca(self): self.maxDiff = None enc = tools_encdec() cl = TPML_CCA( [ (TPMA_CC.COMMANDINDEX_MASK & TPM2_CC.HMAC) | (TPMA_CC.RESERVED1_MASK & (0x3B << 16)) | (TPMA_CC.CHANDLES_MASK & (0x3 << TPMA_CC.CHANDLES_SHIFT)) | TPMA_CC.V | (TPMA_CC.RES_MASK & (0x3 << TPMA_CC.RES_SHIFT)) ] ) ev = enc.encode(cl) self.assertEqual( ev, { "TPM2_CC_HMAC": { "value": 0xE63B0155, "commandIndex": 0x155, "reserved1": 0x3B, "nv": 0, "extensive": 0, "flushed": 0, "cHandles": 0x3, "rHandle": 0, "V": 1, "Res": 0x3, }, }, ) def test_tools_tpml_pcr_selection(self): enc = tools_encdec() pl = TPML_PCR_SELECTION( [ TPMS_PCR_SELECTION.parse("sha1:0,2,4,22"), TPMS_PCR_SELECTION.parse("sha256:1,3,5,23"), ] ) ev = enc.encode(pl) self.assertEqual( ev, {"selected-pcrs": [{"sha1": [0, 2, 4, 22]}, {"sha256": [1, 3, 5, 23],}]}, ) def test_tools_tpml_tagged_tpm_property(self): self.maxDiff = None enc = tools_encdec() pl = TPML_TAGGED_TPM_PROPERTY( [ TPMS_TAGGED_PROPERTY(property=TPM2_PT.LEVEL, value=9001), TPMS_TAGGED_PROPERTY( property=TPM2_PT.FAMILY_INDICATOR, value=0x332E3100 ), TPMS_TAGGED_PROPERTY(property=TPM2_PT.REVISION, value=455), TPMS_TAGGED_PROPERTY(property=TPM2_PT.MANUFACTURER, value=0x54657374), TPMS_TAGGED_PROPERTY( property=TPM2_PT.MODES, value=TPMA_MODES.FIPS_140_2 ), TPMS_TAGGED_PROPERTY(property=TPM2_PT_VENDOR.STRING_4, value=0), TPMS_TAGGED_PROPERTY(property=TPM2_PT.PERMANENT, value=0xFFFFFFFF), TPMS_TAGGED_PROPERTY(property=TPM2_PT.STARTUP_CLEAR, value=0xFFFFFFFF), TPMS_TAGGED_PROPERTY(property=TPM2_PT_NV.COUNTERS_AVAIL, value=9001), ], ) ev = enc.encode(pl) self.assertEqual( ev, { "TPM2_PT_LEVEL": {"raw": 9001}, "TPM2_PT_FAMILY_INDICATOR": {"raw": 0x332E3100, "value": "3.1"}, "TPM2_PT_REVISION": {"raw": 0x1C7, "value": 4.55}, "TPM2_PT_MANUFACTURER": {"raw": 0x54657374, "value": "Test"}, "TPM2_PT_MODES": {"raw": 0x1, "value": "TPMA_MODES_FIPS_140_2"}, "TPM2_PT_VENDOR_STRING_4": {"raw": 0x0, "value": ""}, "TPM2_PT_PERMANENT": { "ownerAuthSet": 1, "endorsementAuthSet": 1, "lockoutAuthSet": 1, "reserved1": 1, "disableClear": 1, "inLockout": 1, "tpmGeneratedEPS": 1, "reserved2": 1, }, "TPM2_PT_STARTUP_CLEAR": { "phEnable": 1, "shEnable": 1, "ehEnable": 1, "phEnableNV": 1, "reserved1": 1, "orderly": 1, }, "TPM2_PT_NV_COUNTERS_AVAIL": 0x2329, }, ) def test_tools_tpml_ecc_curve(self): enc = tools_encdec() el = TPML_ECC_CURVE([TPM2_ECC.NIST_P521, TPM2_ECC.SM2_P256]) ev = enc.encode(el) self.assertEqual(ev, {"TPM2_ECC_NIST_P521": 0x5, "TPM2_ECC_SM2_P256": 0x20}) def test_tools_tpml_handle(self): enc = tools_encdec() hl = TPML_HANDLE([TPM2_RH.OWNER, 0x81000000, 0xF]) ev = enc.encode(hl) self.assertEqual(ev, [0x40000001, 0x81000000, 0xF]) def test_to_yaml(self): pl = TPML_PCR_SELECTION( [TPMS_PCR_SELECTION.parse("sha1:0"), TPMS_PCR_SELECTION.parse("sha256:1")] ) yml = to_yaml(pl) self.assertEqual(yml, "selected-pcrs:\n- sha1:\n - 0\n- sha256:\n - 1\n") def test_tools_tpms_context(self): enc = tools_encdec() ch = "BADCC0DE000000014000000180000000000000000000031503300000000002A20020BD6A5850A4FDFFBB180601EADDACFC446562AD2763A68279E71891A7B8FDE23B027E6F2848DD84D5AD62FB282A6D5F9C108E67C1EA18581747E31A20C4FED2CD806F8A817A1A379C105BE24EBE639C695566D1488C00FE7E9249069B7ACFFCF34AA640B0C4F6D4818319A5A16CACE56F7AA5138732B7406C7ADCFEB4FBBA986A6B12186A75A192C02B7CF0F6C19C459E1EC4EBBA06893A6EF61005E3C92D598E55686F8B2796A46BEF95C88643C26FBD6E57A282588AF8A83D5976D938BFD5C6B50E1BDB27AAB87ADA4B4EEFEA4BDE98E7B53FD4A536A5B9B5578033F17B105DE4EB043A49B1427273E92C0607FCCEC14ADC584A2576AA55C0610F036394FED299E725E708BF7C4A130735A69C13C664137BB614B24E1914FD8F3182E0105B79A47C3C9D8E34D2BDAAAD87010F81499D731B2A83B33C963D12B4F9C9BD6420B6481B8FEC114C0A5B8B344D0D2E8AE5D612840E17A24507ACF6F1A2D457DE44D8613579992CC474CC79DED932397BA04844D2F748A243E6CE99F269D07673C67AD40D3D9C093F7D9DCEE7CACF8B1A72327AD935539DCB18A8876DBDD10A6AB7512A6372DEDCE90298042B53C9ABB0F573344906529DE4574215547754515906F76C5E6A515EDDF878FF7CE45A8B1B76CB54D7E68428A509145223AFAB285A06D39E8348BBDA04DBE78E38DEC01EB8B06E6A65603F3D4D3B79123E70F1CA8199712ACDF18B2FA71B199B12B8C6D8F1737CAA68A76BD8DA33B1735EB41AA62112006D0E28744D81D9437B8919F2E490969ED72470557288AE772440EC80BD3E48878889E0683C1DF3CA117BE0F68BC6197FE4483695C797F7A7369EAC7C357B62A0FC6C0DB3DFB56272DCD601B2D0F10911A2E8B91ADD8AC7127D7CB5EFE3C3E145FFB4A283541CEAAEFF0F15FAC1E2D4A66855B9D44BBB5B017463C02A517143D50000800000FF0022000BF6833B300E4908B4F760109BC1FBBD4A551FCEB7678057B50092F3ED1CEF872B0000000100580023000B00040060000000100018000B0003001000205EA29C688EA872D49AB05B876468EEC6B9EA994DA4EE5626C49DFA240E5160AE00205532E6FD5408C395D59C7067A9DF121BA95652FB0F6A1A3F8E8F07797A49F0DA" cb = unhexlify(ch) ctx = TPMS_CONTEXT.from_tools(cb) ev = enc.encode(ctx) self.assertEqual( ev, { "version": 1, "hierarchy": "owner", "handle": "0x80000000 (2147483648)", "sequence": 789, "contextBlob": {"size": 816}, }, ) def test_tools_pcr_tuple(self): enc = tools_encdec() sels = TPML_PCR_SELECTION.parse("sha1:0,1,2,3+sha256:4,5,6,7") digs = TPML_DIGEST() for i in range(0, 4): digs[i] = TPM2B_DIGEST(i.to_bytes(1, "big") * 20) digs.count += 1 for i in range(4, 8): digs[i] = TPM2B_DIGEST(i.to_bytes(1, "big") * 32) digs.count += 1 ev = enc.encode((sels, digs)) self.assertEqual( ev, { "sha1": { 0: 0, 1: 0x0101010101010101010101010101010101010101, 2: 0x0202020202020202020202020202020202020202, 3: 0x0303030303030303030303030303030303030303, }, "sha256": { 4: 0x0404040404040404040404040404040404040404040404040404040404040404, 5: 0x0505050505050505050505050505050505050505050505050505050505050505, 6: 0x0606060606060606060606060606060606060606060606060606060606060606, 7: 0x0707070707070707070707070707070707070707070707070707070707070707, }, }, ) def test_tools_pcr_tuples(self): enc = tools_encdec() tuples = [ (TPML_PCR_SELECTION.parse("sha1:0"), TPML_DIGEST([b"\x00" * 20])), (TPML_PCR_SELECTION.parse("sha256:1"), TPML_DIGEST([b"\x01" * 32])), ] ev = enc.encode(tuples) self.assertEqual( ev, { "sha1": {0: 0}, "sha256": { 1: 0x0101010101010101010101010101010101010101010101010101010101010101, }, }, ) def test_tools_decode_tpml_handle(self): if not self.has_tools: self.skipTest("tools not in path") yml = self.run_tool("getcap", "handles-pcr") hl = from_yaml(yml, TPML_HANDLE()) self.assertEqual(list(hl), list(range(0, 24))) def test_tools_decode_tpml_ecc_curve(self): if not self.has_tools: self.skipTest("tools not in path") elif not self.tpm.tcti_name_conf.startswith("swtpm"): self.skipTest("swtpm required") yml = self.run_tool("getcap", "ecc-curves") el = from_yaml(yml, TPML_ECC_CURVE()) self.assertEqual( list(el), [ TPM2_ECC.NIST_P192, TPM2_ECC.NIST_P224, TPM2_ECC.NIST_P256, TPM2_ECC.NIST_P384, TPM2_ECC.NIST_P521, TPM2_ECC.BN_P256, TPM2_ECC.BN_P638, TPM2_ECC.SM2_P256, ], ) def test_tools_decode_tpml_alg_property(self): if not self.has_tools: self.skipTest("tools not in path") elif not self.tpm.tcti_name_conf.startswith("swtpm"): self.skipTest("swtpm required") yml = self.run_tool("getcap", "algorithms") al = from_yaml(yml, TPML_ALG_PROPERTY()) self.assertEqual(al[0].alg, TPM2_ALG.RSA) self.assertEqual( al[0].algProperties, TPMA_ALGORITHM.ASYMMETRIC | TPMA_ALGORITHM.OBJECT ) self.assertEqual(al[2].alg, TPM2_ALG.SHA1) self.assertEqual(al[2].algProperties, TPMA_ALGORITHM.HASH) def test_tools_decode_tmpl_pcr_selection(self): if not self.has_tools: self.skipTest("tools not in path") yml = self.run_tool("getcap", "pcrs") pl = from_yaml(yml, TPML_PCR_SELECTION()) self.assertEqual(pl[0].hash, TPM2_ALG.SHA1) self.assertEqual(pl[0].sizeofSelect, 3) self.assertEqual(bytes(pl[0].pcrSelect), b"\xFF\xFF\xFF\x00") self.assertEqual(pl[1].hash, TPM2_ALG.SHA256) self.assertEqual(pl[1].sizeofSelect, 3) self.assertEqual(bytes(pl[1].pcrSelect), b"\xFF\xFF\xFF\x00") def test_tools_decode_tpml_cca(self): if not self.has_tools: self.skipTest("tools not in path") yml = self.run_tool("getcap", "commands") cl = from_yaml(yml, TPML_CCA()) self.assertEqual(cl[0], TPMA_CC(0x440011F)) self.assertEqual(cl[1], TPMA_CC(0x4400120)) def test_tools_decode_tpml_tagged_tpm_property(self): if not self.has_tools: self.skipTest("tools not in path") elif not self.tpm.tcti_name_conf.startswith("swtpm"): self.skipTest("swtpm required") fixedyml = self.run_tool("getcap", "properties-fixed") fl = from_yaml(fixedyml, TPML_TAGGED_TPM_PROPERTY()) self.assertEqual(fl[0].property, TPM2_PT.FAMILY_INDICATOR) self.assertEqual(fl[0].value, 0x322E3000) self.assertEqual(fl[1].property, TPM2_PT.LEVEL) self.assertEqual(fl[1].value, 0) self.assertEqual(fl[2].property, TPM2_PT.REVISION) self.assertEqual(fl[2].value, 0xA4) varyml = self.run_tool("getcap", "properties-variable") vl = from_yaml(varyml, TPML_TAGGED_TPM_PROPERTY()) self.assertEqual(vl[0].property, TPM2_PT.PERMANENT) self.assertEqual(vl[0].value, TPMA_PERMANENT.TPMGENERATEDEPS) self.assertEqual(vl[1].property, TPM2_PT.STARTUP_CLEAR) self.assertEqual( vl[1].value, TPMA_STARTUP.CLEAR_PHENABLE | TPMA_STARTUP.CLEAR_SHENABLE | TPMA_STARTUP.CLEAR_EHENABLE | TPMA_STARTUP.CLEAR_PHENABLENV | TPMA_STARTUP.CLEAR_ORDERLY, ) self.assertEqual(vl[2].property, TPM2_PT_HR.NV_INDEX) self.assertEqual(vl[2].value, 0) def test_tools_decode_tpms_nv_public(self): if not self.has_tools: self.skipTest("tools not in path") self.run_tool("nvdefine", "-s", "8", "-g", "sha256", "0x1800004") yml = self.run_tool("nvreadpublic") nvp = from_yaml(yml, TPMS_NV_PUBLIC()) self.assertEqual(nvp.nvIndex, 0x1800004) self.assertEqual(nvp.nameAlg, TPM2_ALG.SHA256) self.assertEqual(nvp.attributes, 0x60006) self.assertEqual(nvp.dataSize, 8) def test_tools_decode_tpmt_public(self): if not self.has_tools: self.skipTest("tools not in path") rsayml = self.run_tool( "createprimary", "-G", "rsa2048:rsapss-sha256:null", "-a", "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign", ) rsapub = from_yaml(rsayml, TPMT_PUBLIC()) self.assertEqual(rsapub.nameAlg, TPM2_ALG.SHA256) self.assertEqual(rsapub.objectAttributes, TPMA_OBJECT(0x40072)) self.assertEqual(rsapub.type, TPM2_ALG.RSA) self.assertEqual(rsapub.parameters.rsaDetail.exponent, 0) self.assertEqual(rsapub.parameters.rsaDetail.keyBits, 2048) self.assertEqual(rsapub.parameters.rsaDetail.scheme.scheme, TPM2_ALG.RSAPSS) self.assertEqual( rsapub.parameters.rsaDetail.scheme.details.anySig.hashAlg, TPM2_ALG.SHA256 ) self.assertEqual(rsapub.parameters.rsaDetail.symmetric.algorithm, TPM2_ALG.NULL) self.assertEqual(rsapub.parameters.rsaDetail.symmetric.mode.sym, TPM2_ALG.ERROR) self.assertEqual(rsapub.parameters.rsaDetail.symmetric.keyBits.sym, 0) self.assertEqual(len(rsapub.unique.rsa), 256) eccyml = self.run_tool( "createprimary", "-G", "ecc:ecdaa-sha256:null", "-g", "sha1", "-a", "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign", ) eccpub = from_yaml(eccyml, TPMT_PUBLIC()) self.assertEqual(eccpub.nameAlg, TPM2_ALG.SHA1) self.assertEqual(eccpub.objectAttributes, TPMA_OBJECT(0x40072)) self.assertEqual(eccpub.type, TPM2_ALG.ECC) self.assertEqual(eccpub.parameters.eccDetail.curveID, TPM2_ECC.NIST_P256) self.assertEqual(eccpub.parameters.eccDetail.kdf.scheme, TPM2_ALG.NULL) self.assertEqual( eccpub.parameters.eccDetail.kdf.details.mgf1.hashAlg, TPM2_ALG.ERROR ) self.assertEqual(eccpub.parameters.eccDetail.scheme.scheme, TPM2_ALG.ECDAA) self.assertEqual( eccpub.parameters.eccDetail.scheme.details.ecdaa.hashAlg, TPM2_ALG.SHA256 ) self.assertEqual(eccpub.parameters.eccDetail.scheme.details.ecdaa.count, 0) self.assertEqual(eccpub.parameters.eccDetail.symmetric.algorithm, TPM2_ALG.NULL) self.assertEqual(eccpub.parameters.eccDetail.symmetric.mode.sym, TPM2_ALG.ERROR) self.assertEqual(eccpub.parameters.eccDetail.symmetric.keyBits.sym, 0) self.assertEqual(len(eccpub.unique.ecc.x), 32) self.assertEqual(len(eccpub.unique.ecc.y), 32) keyedyml = self.run_tool( "createprimary", "-G", "hmac", "-a", "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign", ) keyedpub = from_yaml(keyedyml, TPMT_PUBLIC()) self.assertEqual(keyedpub.nameAlg, TPM2_ALG.SHA256) self.assertEqual(keyedpub.objectAttributes, TPMA_OBJECT(0x40072)) self.assertEqual(keyedpub.type, TPM2_ALG.KEYEDHASH) self.assertEqual( keyedpub.parameters.keyedHashDetail.scheme.scheme, TPM2_ALG.HMAC ) self.assertEqual( keyedpub.parameters.keyedHashDetail.scheme.details.hmac.hashAlg, TPM2_ALG.SHA256, ) self.assertEqual(len(keyedpub.unique.keyedHash), 32) self.run_tool("flushcontext", "-t") symyml = self.run_tool( "createprimary", "-G", "aes128cfb", "-a", "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|decrypt", ) sympub = from_yaml(symyml, TPMT_PUBLIC()) self.assertEqual(sympub.type, TPM2_ALG.SYMCIPHER) self.assertEqual(sympub.nameAlg, TPM2_ALG.SHA256) self.assertEqual(sympub.objectAttributes, TPMA_OBJECT(0x20072)) self.assertEqual(sympub.parameters.symDetail.sym.algorithm, TPM2_ALG.AES) self.assertEqual(sympub.parameters.symDetail.sym.mode.sym, TPM2_ALG.CFB) self.assertEqual(sympub.parameters.symDetail.sym.keyBits.sym, 128) self.assertEqual(len(sympub.unique.sym), 32) def test_tools_decode_pcr_tuples(self): self.maxDiff = None if not self.has_tools: self.skipTest("tools not in path") yml = self.run_tool("pcrread", "sha1:0,1,2,3,4,5,6,7,8+sha256:0") pcrs = from_yaml(yml, (TPML_PCR_SELECTION(), TPML_DIGEST())) self.assertEqual(len(pcrs), 2) self.assertEqual(pcrs[0][0].count, 1) self.assertEqual(pcrs[0][0][0].hash, TPM2_ALG.SHA1) self.assertEqual(pcrs[0][0][0].sizeofSelect, 1) self.assertEqual(len(pcrs[0][1]), 8) self.assertEqual(pcrs[0][1][0], b"\00" * 20) self.assertEqual(pcrs[0][1][1], b"\00" * 20) self.assertEqual(pcrs[0][1][2], b"\00" * 20) self.assertEqual(pcrs[0][1][3], b"\00" * 20) self.assertEqual(pcrs[0][1][4], b"\00" * 20) self.assertEqual(pcrs[0][1][5], b"\00" * 20) self.assertEqual(pcrs[0][1][6], b"\00" * 20) self.assertEqual(pcrs[0][1][7], b"\00" * 20) self.assertEqual(pcrs[1][0][0].hash, TPM2_ALG.SHA1) self.assertEqual(pcrs[1][0][0].sizeofSelect, 2) self.assertEqual(pcrs[1][0][1].hash, TPM2_ALG.SHA256) self.assertEqual(pcrs[1][0][1].sizeofSelect, 1) self.assertEqual(len(pcrs[1][1]), 2) self.assertEqual(pcrs[1][1][0], b"\00" * 20) self.assertEqual(pcrs[1][1][1], b"\00" * 32) def test_tools_tpma_session(self): enc = tools_encdec() ev = enc.encode(TPMA_SESSION.AUDIT | TPMA_SESSION.ENCRYPT) self.assertEqual(ev, {"Session-Attributes": "encrypt|audit"}) def test_tools_decode_tpma_session(self): if not self.has_tools: self.skipTest("tools not in path") session_path = os.path.join( self.tpm.working_dir.name, "test_decode_tpma_session.ctx" ) self.run_tool("startauthsession", "-S", session_path) self.run_tool( "sessionconfig", "--enable-decrypt", "--enable-audit", session_path, ) yml = self.run_tool("sessionconfig", session_path) attrs = from_yaml(yml, TPMA_SESSION()) self.assertEqual( attrs, TPMA_SESSION.DECRYPT | TPMA_SESSION.CONTINUESESSION | TPMA_SESSION.AUDIT, ) def test_tools_tpml_digest_values(self): enc = tools_encdec() vals = TPML_DIGEST_VALUES( [ TPMT_HA(hashAlg=TPM2_ALG.SHA1, digest=TPMU_HA(sha512=b"\x01" * 20)), TPMT_HA(hashAlg=TPM2_ALG.SHA256, digest=TPMU_HA(sha512=b"\x02" * 32)), ] ) ev = enc.encode(vals) self.assertEqual( ev, {"sha1": "01" * 20, "sha256": "02" * 32}, ) def test_tools_decode_tpml_digest_values(self): if not self.has_tools: self.skipTest("tools not in path") data_path = os.path.join(self.tpm.working_dir.name, "eventdata") with open(data_path, "w") as f: f.write("falafel") yml = self.run_tool("pcrevent", "8", data_path) dv = from_yaml(yml, TPML_DIGEST_VALUES()) self.assertEqual(len(dv), 4) self.assertEqual(dv[0].hashAlg, TPM2_ALG.SHA1) self.assertEqual( bytes(dv[0]), unhexlify("49477eefc260670d35faf60f885f7f0bb9bd6f6e") ) self.assertEqual(dv[1].hashAlg, TPM2_ALG.SHA256) self.assertEqual( bytes(dv[1]), unhexlify( "b0a1499eaed4edb2b4893dfa2ac2a4ba26c7db0e64d1c8dcc1ae092a70ff1538" ), ) self.assertEqual(dv[2].hashAlg, TPM2_ALG.SHA384) self.assertEqual( bytes(dv[2]), unhexlify( "69a3a8e70031302b15978079ca7780db5d36d6f8b637838c876ae3fa6464f0359d8ab2f0d4dc8d56ed8ecf4661249cc4" ), ) self.assertEqual(dv[3].hashAlg, TPM2_ALG.SHA512) self.assertEqual( bytes(dv[3]), unhexlify( "d9a6a0417a7461907ccdcfe53cda43c8a4e816b00190bae1b3608c209542c91b3239968a5b5620c3c5748849964a561e5a871bb62f556883ae60e11bc1f52942" ), ) def test_tools_tpml_alg(self): enc = tools_encdec() vals = TPML_ALG([TPM2_ALG.SHA1, TPM2_ALG.RSA]) ev = enc.encode(vals) self.assertEqual(ev, {"remaining": "sha1 rsa"}) def test_tools_decode_tpml_alg(self): if not self.has_tools: self.skipTest("tools not in path") elif not self.tpm.tcti_name_conf.startswith("swtpm"): self.skipTest("swtpm required") self.run_tool("incrementalselftest", "rsa", "ecc") yml = self.run_tool("incrementalselftest") al = from_yaml(yml, TPML_ALG()) self.assertIn(TPM2_ALG.RSAPSS, al) self.assertIn(TPM2_ALG.RSASSA, al) def test_tools_tpm2b_name(self): enc = tools_encdec() name = TPM2_ALG.SHA1.to_bytes(2, "big") + b"\xFF" * 20 name2b = TPM2B_NAME(name) hn = hexlify(name).decode("ascii") ev = enc.encode(name2b) self.assertEqual(ev, {"name": hn}) def test_tools_decode_tpm2b_name(self): if not self.has_tools: self.skipTest("tools not in path") key = ec.generate_private_key(ec.SECP256R1()).public_key() kb = key.public_bytes( serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo ) key_path = os.path.join(self.tpm.working_dir.name, "external.key") ctx_path = os.path.join(self.tpm.working_dir.name, "external.ctx") with open(key_path, "wb") as f: f.write(kb) yml = self.run_tool("loadexternal", "-G", "ecc", "-u", key_path, "-c", ctx_path) name = from_yaml(yml, TPM2B_NAME()) self.assertEqual(len(name), 34) self.assertEqual(name[0:2], b"\x00\x0b") def test_decode_int(self): v = from_yaml("1234", int(0)) self.assertEqual(v, 1234) def test_decode_int_nt(self): if not self.has_tools: self.skipTest("tools not in path") elif self.tools_version < TSS2Version("5.3"): self.skipTest("tpm2-tools version 5.3 or later required") self.run_tool("nvdefine", "0x01000000", "-a", "authwrite|authread|nt=bits") self.run_tool("nvsetbits", "0x01000000", "-i", "0x4000000000000001") yml = self.run_tool("nvread", "0x01000000", "--print-yaml", "-s", "8") v = from_yaml(yml, int(0)) self.assertEqual(v, 0x4000000000000001) self.run_tool("nvdefine", "0x01200000", "-a", "authwrite|authread|nt=counter") self.run_tool("nvincrement", "0x01200000") yml = self.run_tool("nvread", "0x01200000", "--print-yaml", "-s", "8") v = from_yaml(yml, int(0)) self.assertEqual(v, 1) def test_decode_nt_extend(self): if not self.has_tools: self.skipTest("tools not in path") elif self.tools_version < TSS2Version("5.3"): self.skipTest("tpm2-tools version 5.3 or later required") self.run_tool( "nvdefine", "0x01000000", "-g", "sha256", "-a", "authwrite|authread|nt=extend", ) extend_path = os.path.join(self.tpm.working_dir.name, "extend_data") with open(extend_path, "wb") as f: f.write(b"falafel") self.run_tool("nvextend", "0x01000000", "-i", extend_path) yml = self.run_tool("nvread", "0x01000000", "--print-yaml", "-s", "32") v = from_yaml(yml, TPMT_HA()) self.assertEqual(v.hashAlg, TPM2_ALG.SHA256) self.assertEqual( bytes(v), b"\xc5r\x87#\xa3\xbbW\x91m\xb9\xe5\xde\xa9\x01\tLc\xa9`Y\x8a\x8a)\xfe'z\xee_j\x8e\xe7\xce", ) def test_decode_nt_pin(self): if not self.has_tools: self.skipTest("tools not in path") elif self.tools_version < TSS2Version("5.3"): self.skipTest("tpm2-tools version 5.3 or later required") self.run_tool( "nvdefine", "0x01000000", "-C", "o", "-a", "ownerwrite|ownerread|nt=pinfail|no_da", ) pfail = TPMS_NV_PIN_COUNTER_PARAMETERS(pinCount=1234, pinLimit=5678) fb = pfail.marshal() fail_path = os.path.join(self.tpm.working_dir.name, "pinfail_data") with open(fail_path, "wb") as f: f.write(fb) self.run_tool("nvwrite", "0x01000000", "-C", "o", "-i", fail_path) yml = self.run_tool( "nvread", "0x01000000", "-C", "o", "--print-yaml", "-s", "8" ) print(yml) v = from_yaml(yml, TPMS_NV_PIN_COUNTER_PARAMETERS()) self.assertEqual(v.pinCount, 1234) self.assertEqual(v.pinLimit, 5678) self.run_tool( "nvdefine", "0x01200000", "-C", "o", "-a", "ownerwrite|ownerread|nt=pinpass|no_da", ) ppass = TPMS_NV_PIN_COUNTER_PARAMETERS(pinCount=8765, pinLimit=4321) pb = ppass.marshal() pass_path = os.path.join(self.tpm.working_dir.name, "pinpass_data") with open(pass_path, "wb") as f: f.write(pb) self.run_tool("nvwrite", "0x01200000", "-C", "o", "-i", pass_path) yml = self.run_tool( "nvread", "0x01200000", "-C", "o", "--print-yaml", "-s", "8" ) v = from_yaml(yml, TPMS_NV_PIN_COUNTER_PARAMETERS()) self.assertEqual(v.pinCount, 8765) self.assertEqual(v.pinLimit, 4321) def test_tools_nt_pin(self): enc = tools_encdec() pin = TPMS_NV_PIN_COUNTER_PARAMETERS(pinCount=1234, pinLimit=5678) ev = enc.encode(pin) self.assertEqual(ev, {"pinCount": 1234, "pinLimit": 5678}) def test_tools_unsupported(self): dlyml = """ - FF00 """ with self.assertRaises(ValueError) as e: from_yaml(dlyml, TPML_DIGEST()) self.assertEqual(str(e.exception), "unsupported list TPML_DIGEST") tsyml = """ sensitiveType: test """ with self.assertRaises(ValueError) as e: from_yaml(tsyml, TPMT_SENSITIVE()) self.assertEqual(str(e.exception), "unsupported structure TPMT_SENSITIVE") with self.assertRaises(ValueError) as e: to_yaml(TPML_DIGEST()) self.assertEqual(str(e.exception), "unsupported list TPML_DIGEST") with self.assertRaises(ValueError) as e: to_yaml(TPMT_SENSITIVE()) self.assertEqual(str(e.exception), "unsupported structure TPMT_SENSITIVE") if __name__ == "__main__": unittest.main() tpm2-pytss-2.3.0/test/test_esapi.py000066400000000000000000005140511463722220500172600ustar00rootroot00000000000000#!/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" }} ] }} """ 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-2.3.0/test/test_import.py000066400000000000000000000031041463722220500174610ustar00rootroot00000000000000#!/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 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 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 self.assertEqual(e.exception.msg, "/bin/ls: not a: teapot") tpm2-pytss-2.3.0/test/test_internal.py000066400000000000000000000117521463722220500177730ustar00rootroot00000000000000#!/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-2.3.0/test/test_policy.py000066400000000000000000000747271463722220500174710ustar00rootroot00000000000000#!/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 secp129r1") 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 secp129r1") 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-2.3.0/test/test_tcti.py000066400000000000000000000152151463722220500171200ustar00rootroot00000000000000#!/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-2.3.0/test/test_tcti_spi_helper.py000066400000000000000000000112341463722220500213270ustar00rootroot00000000000000#!/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-2.3.0/test/test_tsskey.py000066400000000000000000000107431463722220500175000ustar00rootroot00000000000000#!/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-2.3.0/test/test_types.py000066400000000000000000002234611463722220500173250ustar00rootroot00000000000000#!/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( f"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( f"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.iterator())), 0) def test_TPM_FRIENDLY_INT_contains(self): self.assertTrue(TPM2_CC.contains(TPM2_CC.AC_Send)) 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 | 0x00090000 ) with self.assertRaises(ValueError) as e: str(badattrs) self.assertEqual(str(e.exception), "unnmatched values left: 0x80000") 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"") if __name__ == "__main__": unittest.main() tpm2-pytss-2.3.0/test/test_utils.py000066400000000000000000000725651463722220500173300ustar00rootroot00000000000000#!/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 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") cert_index, def_template = _ek.EK_HIGH_RSA2048 nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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, template = create_ek_template("EK-HIGH-RSA2048", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(template.marshal(), def_template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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") cert_index, def_template = _ek.EK_HIGH_ECC256 nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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, template = create_ek_template("EK-HIGH-ECC256", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(template.marshal(), def_template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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-ECC256", 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_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") cert_index, def_template = _ek.EK_HIGH_ECC384 nv_cert = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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, template = create_ek_template("EK-HIGH-ECC384", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual(template.marshal(), def_template.marshal()) tb = ek_test_template.marshal() nv_template = TPM2B_NV_PUBLIC( nvPublic=TPMS_NV_PUBLIC( nvIndex=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-ECC384", nv_read) self.assertEqual(cert, b"I am a certificate") self.assertEqual( 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()