From c2c78d10bf92aa339d7764e430defddfb826decd Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 15:10:46 -0600 Subject: [PATCH 1/7] mypy: setup for static analysis mypy is a static analyzer for Python using the Python3 typehints as meta data. See the below link for more information: - https://mypy.readthedocs.io/en/stable/index.html Signed-off-by: William Roberts --- .ci/run.sh | 6 ++++++ setup.cfg | 4 ++++ src/tpm2_pytss/py.typed | 0 3 files changed, 10 insertions(+) create mode 100644 src/tpm2_pytss/py.typed diff --git a/.ci/run.sh b/.ci/run.sh index 1ad9abff..95a93915 100755 --- a/.ci/run.sh +++ b/.ci/run.sh @@ -103,6 +103,10 @@ function run_style() { "${PYTHON}" -m black --diff --check "${SRC_ROOT}" } +function run_mypy_check() { + "${PYTHON}" -m mypy --ignore-missing-imports "${SRC_ROOT}" +} + if [ "x${TEST}" != "x" ]; then run_test elif [ "x${WHITESPACE}" != "x" ]; then @@ -111,4 +115,6 @@ elif [ "x${STYLE}" != "x" ]; then run_style elif [ "x${PUBLISH_PKG}" != "x" ]; then run_publish_pkg +elif [ "x${MYPY}" != "x" ]; then + run_mypy_check fi diff --git a/setup.cfg b/setup.cfg index 673f7917..126172a0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -39,6 +39,9 @@ install_requires = packaging pyyaml +[options.package_data] +tpm2_pytss = py.typed + [options.extras_require] dev = @@ -56,3 +59,4 @@ dev = myst-parser build installer + mypy diff --git a/src/tpm2_pytss/py.typed b/src/tpm2_pytss/py.typed new file mode 100644 index 00000000..e69de29b From 38d9535b1d7fcaf5fff276fbc1745e877a8849fb Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 15:17:13 -0600 Subject: [PATCH 2/7] ci: add a mypy checker Signed-off-by: William Roberts --- .github/workflows/tests.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d8f0ca85..ad024776 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -87,3 +87,24 @@ jobs: env: STYLE: 1 run: ./.ci/run.sh + + mypy-check: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Install dependencies + env: + TPM2_TSS_VERSION: master + TPM2_TSS_FAPI: true + TPM2_TOOLS_VERSION: master + run: ./.ci/install-deps.sh + + - name: Install tpm2-pytss + run: pip install -e .[dev] + + - name: MyPy Check + env: + MYPY: 1 + run: ./.ci/run.sh From ebcd8272085b94ea236734e6e406856aceb830d5 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 15:22:28 -0600 Subject: [PATCH 3/7] test_fapi.py: fix mypy errors Fixes: test/test_fapi.py:84: error: Incompatible types in assignment (expression has type "bytes", variable has type "Hash") test/test_fapi.py:85: error: Incompatible return value type (got "Hash", expected "bytes") Signed-off-by: William Roberts --- test/test_fapi.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_fapi.py b/test/test_fapi.py index 3ba569f4..f9d72a11 100644 --- a/test/test_fapi.py +++ b/test/test_fapi.py @@ -81,8 +81,7 @@ 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 + return digest.finalize() # TODO unprovisioned tests From dc1efc21dade364cd5488b800e2c93b7f4b27c93 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 15:37:42 -0600 Subject: [PATCH 4/7] mypy: drop option --ignore-missing-imports Drop the nuclear option of --ignore-missing-imports and add a more targeted approach to ignoring libraries without type information. This just makes sure that tpm2-pytss internal modules themselves don't accidentally get ignored. Signed-off-by: William Roberts --- .ci/run.sh | 2 +- setup.cfg | 1 + setup.py | 6 +++--- test/test_tsskey.py | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.ci/run.sh b/.ci/run.sh index 95a93915..d023a689 100755 --- a/.ci/run.sh +++ b/.ci/run.sh @@ -104,7 +104,7 @@ function run_style() { } function run_mypy_check() { - "${PYTHON}" -m mypy --ignore-missing-imports "${SRC_ROOT}" + "${PYTHON}" -m mypy "${SRC_ROOT}" } if [ "x${TEST}" != "x" ]; then diff --git a/setup.cfg b/setup.cfg index 126172a0..48e5c937 100644 --- a/setup.cfg +++ b/setup.cfg @@ -60,3 +60,4 @@ dev = build installer mypy + types-pycparser diff --git a/setup.py b/setup.py index 59dbc14f..145165da 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ 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 ( +from pkgconfig import pkgconfig # type: ignore +from pycparser import c_parser, preprocess_file # type: ignore +from pycparser.c_ast import ( # type: ignore Typedef, TypeDecl, IdentifierType, diff --git a/test/test_tsskey.py b/test/test_tsskey.py index 683de432..e9e2e4db 100644 --- a/test/test_tsskey.py +++ b/test/test_tsskey.py @@ -3,8 +3,8 @@ 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 +from asn1crypto.core import ObjectIdentifier # type: ignore +from asn1crypto import pem # type: ignore import unittest From 75b7679d11b7f0a99b08cd6b3c9a2201f05214ec Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 15:55:36 -0600 Subject: [PATCH 5/7] tpm2_pytss.internal: add py.typed Signed-off-by: William Roberts --- setup.cfg | 2 +- src/tpm2_pytss/internal/py.typed | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/tpm2_pytss/internal/py.typed diff --git a/setup.cfg b/setup.cfg index 48e5c937..bcb1a2b3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,7 +41,7 @@ install_requires = [options.package_data] tpm2_pytss = py.typed - +tpm2_pytss.internal = py.typed [options.extras_require] dev = diff --git a/src/tpm2_pytss/internal/py.typed b/src/tpm2_pytss/internal/py.typed new file mode 100644 index 00000000..e69de29b From 6e5856719cc01a8f35d394a6f9018cc17aec13c9 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 16:02:01 -0600 Subject: [PATCH 6/7] mypy: get checker working better Signed-off-by: William Roberts --- .ci/run.sh | 2 +- src/tpm2_pytss/TSS2_Exception.py | 5 ++--- src/tpm2_pytss/callbacks.py | 2 +- src/tpm2_pytss/constants.py | 2 +- src/tpm2_pytss/encoding.py | 2 +- src/tpm2_pytss/internal/utils.py | 5 +++-- src/tpm2_pytss/policy.py | 2 +- src/tpm2_pytss/tsskey.py | 2 +- src/tpm2_pytss/types.py | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.ci/run.sh b/.ci/run.sh index d023a689..752e7112 100755 --- a/.ci/run.sh +++ b/.ci/run.sh @@ -104,7 +104,7 @@ function run_style() { } function run_mypy_check() { - "${PYTHON}" -m mypy "${SRC_ROOT}" + "${PYTHON}" -m mypy --exclude=docs --exclude=scripts "${SRC_ROOT}" } if [ "x${TEST}" != "x" ]; then diff --git a/src/tpm2_pytss/TSS2_Exception.py b/src/tpm2_pytss/TSS2_Exception.py index 309e25db..a96d6a4b 100644 --- a/src/tpm2_pytss/TSS2_Exception.py +++ b/src/tpm2_pytss/TSS2_Exception.py @@ -1,12 +1,11 @@ -from ._libtpm2_pytss import lib, ffi +from ._libtpm2_pytss import lib, ffi # type: ignore 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]): + def __init__(self, rc: Union["TSS2_RC", "TPM2_RC", int]): # type: ignore if isinstance(rc, int): # defer this to avoid circular dep. from .constants import TSS2_RC diff --git a/src/tpm2_pytss/callbacks.py b/src/tpm2_pytss/callbacks.py index 23a23e73..5bf3041d 100644 --- a/src/tpm2_pytss/callbacks.py +++ b/src/tpm2_pytss/callbacks.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2 -from ._libtpm2_pytss import lib +from ._libtpm2_pytss import lib # type: ignore from .internal.constants import CALLBACK_BASE_NAME, CALLBACK_COUNT, CallbackType diff --git a/src/tpm2_pytss/constants.py b/src/tpm2_pytss/constants.py index 01a2b844..4364c68a 100644 --- a/src/tpm2_pytss/constants.py +++ b/src/tpm2_pytss/constants.py @@ -6,7 +6,7 @@ Along with helpers to go from string values to constants and constant values to string values. """ -from ._libtpm2_pytss import lib, ffi +from ._libtpm2_pytss import lib, ffi # type: ignore from tpm2_pytss.internal.utils import _CLASS_INT_ATTRS_from_string, _lib_version_atleast diff --git a/src/tpm2_pytss/encoding.py b/src/tpm2_pytss/encoding.py index 210d3abe..6552da60 100644 --- a/src/tpm2_pytss/encoding.py +++ b/src/tpm2_pytss/encoding.py @@ -1,6 +1,6 @@ from binascii import hexlify, unhexlify from typing import Any, Union, List, Dict, Tuple -from ._libtpm2_pytss import ffi +from ._libtpm2_pytss import ffi # type: ignore from .internal.crypto import _get_digest_size from .constants import ( TPM_FRIENDLY_INT, diff --git a/src/tpm2_pytss/internal/utils.py b/src/tpm2_pytss/internal/utils.py index c3dedd6c..7f7ca0c6 100644 --- a/src/tpm2_pytss/internal/utils.py +++ b/src/tpm2_pytss/internal/utils.py @@ -4,11 +4,12 @@ from typing import List from packaging.version import Version, InvalidVersion -from .._libtpm2_pytss import ffi, lib +from .._libtpm2_pytss import ffi, lib # type: ignore from ..TSS2_Exception import TSS2_Exception try: - from .versions import _versions + # This is generated by install, so just ignore it. + from .versions import _versions # type: ignore except ImportError as e: # this is needed so docs can be generated without building if "sphinx" not in sys.modules: diff --git a/src/tpm2_pytss/policy.py b/src/tpm2_pytss/policy.py index 116ba070..92ad3044 100644 --- a/src/tpm2_pytss/policy.py +++ b/src/tpm2_pytss/policy.py @@ -18,7 +18,7 @@ ) from .constants import TPM2_ALG, ESYS_TR, TSS2_RC, TPM2_RC from .TSS2_Exception import TSS2_Exception -from ._libtpm2_pytss import ffi, lib +from ._libtpm2_pytss import ffi, lib # type: ignore from .ESAPI import ESAPI from enum import Enum from typing import Callable, Union diff --git a/src/tpm2_pytss/tsskey.py b/src/tpm2_pytss/tsskey.py index 5ad216f9..9b31c72b 100644 --- a/src/tpm2_pytss/tsskey.py +++ b/src/tpm2_pytss/tsskey.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2 import warnings -from ._libtpm2_pytss import lib +from ._libtpm2_pytss import lib # type: ignore from .types import * from .constants import TPM2_ECC, TPM2_CAP, ESYS_TR from asn1crypto.core import ObjectIdentifier, Sequence, Boolean, OctetString, Integer diff --git a/src/tpm2_pytss/types.py b/src/tpm2_pytss/types.py index d4ecbd73..5c0a3c86 100644 --- a/src/tpm2_pytss/types.py +++ b/src/tpm2_pytss/types.py @@ -9,7 +9,7 @@ of key-value objects where the keys are the names of the associated type. """ -from ._libtpm2_pytss import ffi, lib +from ._libtpm2_pytss import ffi, lib # type: ignore from tpm2_pytss.internal.utils import ( _chkrc, From 336aa1650e4d87adfea66a64496344a3eae240dc Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 21 Nov 2022 17:12:51 -0600 Subject: [PATCH 7/7] mypy: WIP Signed-off-by: William Roberts --- .ci/run.sh | 2 +- setup.cfg | 1 - setup.py | 6 +-- src/tpm2_pytss/TCTI.py | 4 +- src/tpm2_pytss/TCTILdr.py | 2 +- src/tpm2_pytss/TSS2_Exception.py | 5 ++- src/tpm2_pytss/callbacks.py | 2 +- src/tpm2_pytss/constants.py | 17 ++++---- src/tpm2_pytss/encoding.py | 2 +- src/tpm2_pytss/internal/crypto.py | 49 ++++++++++++---------- src/tpm2_pytss/internal/utils.py | 10 ++--- src/tpm2_pytss/policy.py | 2 +- src/tpm2_pytss/tsskey.py | 2 +- src/tpm2_pytss/types.py | 68 ++++++++++++++++--------------- test/test_tsskey.py | 4 +- 15 files changed, 94 insertions(+), 82 deletions(-) diff --git a/.ci/run.sh b/.ci/run.sh index 752e7112..e2bb0a48 100755 --- a/.ci/run.sh +++ b/.ci/run.sh @@ -104,7 +104,7 @@ function run_style() { } function run_mypy_check() { - "${PYTHON}" -m mypy --exclude=docs --exclude=scripts "${SRC_ROOT}" + "${PYTHON}" -m mypy --exclude=docs --exclude=scripts --exclude='setup.py' "${SRC_ROOT}" } if [ "x${TEST}" != "x" ]; then diff --git a/setup.cfg b/setup.cfg index bcb1a2b3..2f7ca373 100644 --- a/setup.cfg +++ b/setup.cfg @@ -60,4 +60,3 @@ dev = build installer mypy - types-pycparser diff --git a/setup.py b/setup.py index 145165da..59dbc14f 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ import os from setuptools import setup from setuptools.command.build_ext import build_ext -from pkgconfig import pkgconfig # type: ignore -from pycparser import c_parser, preprocess_file # type: ignore -from pycparser.c_ast import ( # type: ignore +from pkgconfig import pkgconfig +from pycparser import c_parser, preprocess_file +from pycparser.c_ast import ( Typedef, TypeDecl, IdentifierType, diff --git a/src/tpm2_pytss/TCTI.py b/src/tpm2_pytss/TCTI.py index 360e5280..3d5b01d9 100644 --- a/src/tpm2_pytss/TCTI.py +++ b/src/tpm2_pytss/TCTI.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-2 -from ._libtpm2_pytss import ffi, lib +from ._libtpm2_pytss import ffi, lib # type: ignore[import] from .internal.utils import _chkrc from .constants import TSS2_RC, TPM2_RC @@ -241,7 +241,7 @@ def cancel(self) -> None: _chkrc(self._v1.cancel(self._ctx)) @common_checks() - def get_poll_handles(self) -> Tuple[PollData]: + def get_poll_handles(self) -> Tuple[PollData, ...]: """Gets the poll handles from the TPM. Returns: diff --git a/src/tpm2_pytss/TCTILdr.py b/src/tpm2_pytss/TCTILdr.py index 2f57c803..7f93eb22 100644 --- a/src/tpm2_pytss/TCTILdr.py +++ b/src/tpm2_pytss/TCTILdr.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-2 -from ._libtpm2_pytss import lib, ffi +from ._libtpm2_pytss import lib, ffi # type: ignore[import] from .TCTI import TCTI from .internal.utils import _chkrc diff --git a/src/tpm2_pytss/TSS2_Exception.py b/src/tpm2_pytss/TSS2_Exception.py index a96d6a4b..9444b1da 100644 --- a/src/tpm2_pytss/TSS2_Exception.py +++ b/src/tpm2_pytss/TSS2_Exception.py @@ -1,11 +1,12 @@ -from ._libtpm2_pytss import lib, ffi # type: ignore +from ._libtpm2_pytss import lib, ffi # type: ignore[import] 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]): # type: ignore + def __init__(self, rc: Union["TSS2_RC", "TPM2_RC", int]): # type: ignore[name-defined] if isinstance(rc, int): # defer this to avoid circular dep. from .constants import TSS2_RC diff --git a/src/tpm2_pytss/callbacks.py b/src/tpm2_pytss/callbacks.py index 5bf3041d..b3535823 100644 --- a/src/tpm2_pytss/callbacks.py +++ b/src/tpm2_pytss/callbacks.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2 -from ._libtpm2_pytss import lib # type: ignore +from ._libtpm2_pytss import lib # type: ignore[import] from .internal.constants import CALLBACK_BASE_NAME, CALLBACK_COUNT, CallbackType diff --git a/src/tpm2_pytss/constants.py b/src/tpm2_pytss/constants.py index 4364c68a..0d0d04db 100644 --- a/src/tpm2_pytss/constants.py +++ b/src/tpm2_pytss/constants.py @@ -6,12 +6,13 @@ Along with helpers to go from string values to constants and constant values to string values. """ -from ._libtpm2_pytss import lib, ffi # type: ignore +from ._libtpm2_pytss import lib, ffi # type: ignore[import] from tpm2_pytss.internal.utils import _CLASS_INT_ATTRS_from_string, _lib_version_atleast +from typing import Dict, Tuple class TPM_FRIENDLY_INT(int): - _FIXUP_MAP = {} + _FIXUP_MAP: Dict[str, str] = {} @classmethod def parse(cls, value: str) -> int: @@ -231,7 +232,7 @@ def _fix_const_type(cls): class TPMA_FRIENDLY_INTLIST(TPM_FRIENDLY_INT): - _MASKS = tuple() + _MASKS: Tuple[Tuple[int, int, str], ...] = tuple() @classmethod def parse(cls, value: str) -> int: @@ -392,7 +393,7 @@ class ESYS_TR(TPM_FRIENDLY_INT): RH_PLATFORM = lib.ESYS_TR_RH_PLATFORM RH_PLATFORM_NV = lib.ESYS_TR_RH_PLATFORM_NV - def serialize(self, ectx: "ESAPI") -> bytes: + def serialize(self, ectx: "ESAPI") -> bytes: # type: ignore[name-defined] """Same as see tpm2_pytss.ESAPI.tr_serialize Args: @@ -405,7 +406,7 @@ def serialize(self, ectx: "ESAPI") -> bytes: return ectx.tr_serialize(self) @staticmethod - def deserialize(ectx: "ESAPI", buffer: bytes) -> "ESYS_TR": + def deserialize(ectx: "ESAPI", buffer: bytes) -> "ESYS_TR": # type: ignore[name-defined] """Same as see tpm2_pytss.ESAPI.tr_derialize Args: @@ -417,7 +418,7 @@ def deserialize(ectx: "ESAPI", buffer: bytes) -> "ESYS_TR": return ectx.tr_deserialize(buffer) - def get_name(self, ectx: "ESAPI") -> "TPM2B_NAME": + def get_name(self, ectx: "ESAPI") -> "TPM2B_NAME": # type: ignore[name-defined] """Same as see tpm2_pytss.ESAPI.tr_get_name Args: @@ -428,7 +429,7 @@ def get_name(self, ectx: "ESAPI") -> "TPM2B_NAME": """ return ectx.tr_get_name(self) - def close(self, ectx: "ESAPI"): + def close(self, ectx: "ESAPI"): # type: ignore[name-defined] """Same as see tpm2_pytss.ESAPI.tr_close Args: @@ -1256,7 +1257,7 @@ def parse(cls, value: str) -> "TPMA_LOCALITY": return cls(value, base=0) except ValueError: pass - return super().parse(value) + return TPMA_LOCALITY(super().parse(value)) def __str__(self) -> str: """Given a set of localities or an extended locality, return the string representation diff --git a/src/tpm2_pytss/encoding.py b/src/tpm2_pytss/encoding.py index 6552da60..439441a3 100644 --- a/src/tpm2_pytss/encoding.py +++ b/src/tpm2_pytss/encoding.py @@ -1,6 +1,6 @@ from binascii import hexlify, unhexlify from typing import Any, Union, List, Dict, Tuple -from ._libtpm2_pytss import ffi # type: ignore +from ._libtpm2_pytss import ffi # type: ignore[name-defined] from .internal.crypto import _get_digest_size from .constants import ( TPM_FRIENDLY_INT, diff --git a/src/tpm2_pytss/internal/crypto.py b/src/tpm2_pytss/internal/crypto.py index 93e51813..f49f577b 100644 --- a/src/tpm2_pytss/internal/crypto.py +++ b/src/tpm2_pytss/internal/crypto.py @@ -23,11 +23,21 @@ 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 +from typing import Tuple, Type, Any, Union import secrets import sys -_curvetable = ( +# Despite below, it won't allow us to use the right classes for the +# typehint so we just use Any... +# from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding +# ec.SECP192R1 +# +# type(ec.SECP192R1) +# +# ec.SECP192R1.__bases__ +# (,) + +_curvetable: Tuple[Tuple[TPM2_ECC, Any], ...] = ( (TPM2_ECC.NIST_P192, ec.SECP192R1), (TPM2_ECC.NIST_P224, ec.SECP224R1), (TPM2_ECC.NIST_P256, ec.SECP256R1), @@ -35,7 +45,7 @@ (TPM2_ECC.NIST_P521, ec.SECP521R1), ) -_digesttable = ( +_digesttable: Tuple[Tuple[TPM2_ALG, Any], ...] = ( (TPM2_ALG.SHA1, hashes.SHA1), (TPM2_ALG.SHA256, hashes.SHA256), (TPM2_ALG.SHA384, hashes.SHA384), @@ -48,14 +58,14 @@ if hasattr(hashes, "SM3"): _digesttable += ((TPM2_ALG.SM3_256, hashes.SM3),) -_algtable = ( +_algtable: Tuple[Tuple[TPM2_ALG, Any], ...] = ( (TPM2_ALG.AES, AES), (TPM2_ALG.CAMELLIA, Camellia), (TPM2_ALG.CFB, modes.CFB), ) try: - from cryptography.hazmat.primitives.ciphers.algorithms import SM4 + from cryptography.hazmat.primitives.ciphers.algorithms import SM4 # type: ignore[attr-defined] _algtable += ((TPM2_ALG.SM4, SM4),) except ImportError: @@ -274,8 +284,7 @@ def _generate_d(p, q, e, n): return d -def private_to_key(private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC"): - key = None +def private_to_key(private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC") -> Union[ec.EllipticCurvePrivateKey, rsa.RSAPrivateKey]: # type: ignore[name-defined] if private.sensitiveType == TPM2_ALG.RSA: p = int.from_bytes(bytes(private.sensitive.rsa), byteorder="big") @@ -286,7 +295,7 @@ def private_to_key(private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC") else 65537 ) - key = _MyRSAPrivateNumbers(p, n, e, rsa.RSAPublicNumbers(e, n)).private_key( + return _MyRSAPrivateNumbers(p, n, e, rsa.RSAPublicNumbers(e, n)).private_key( backend=default_backend() ) elif private.sensitiveType == TPM2_ALG.ECC: @@ -301,13 +310,11 @@ def private_to_key(private: "types.TPMT_SENSITIVE", public: "types.TPMT_PUBLIC") 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( + return ec.EllipticCurvePrivateNumbers( p, ec.EllipticCurvePublicNumbers(x, y, curve()) ).private_key(backend=default_backend()) - else: - raise ValueError(f"unsupported key type: {private.sensitiveType}") - return key + raise ValueError(f"unsupported key type: {private.sensitiveType}") def _public_to_pem(obj, encoding="pem"): @@ -535,7 +542,7 @@ def _generate_ecc_seed( return (seed, secret) -def _generate_seed(public: "types.TPMT_PUBLIC", label: bytes) -> Tuple[bytes, bytes]: +def _generate_seed(public: "types.TPMT_PUBLIC", label: bytes) -> Tuple[bytes, bytes]: # type: ignore[name-defined] key = public_to_key(public) if public.type == TPM2_ALG.RSA: return _generate_rsa_seed(key, public.nameAlg, label) @@ -588,8 +595,8 @@ def __ecc_secret_to_seed( def _secret_to_seed( - private: "types.TPMT_SENSITIVE", - public: "types.TPMT_PUBLIC", + private: "types.TPMT_SENSITIVE", # type: ignore[name-defined] + public: "types.TPMT_PUBLIC", # type: ignore[name-defined] label: bytes, outsymseed: bytes, ): @@ -605,7 +612,7 @@ def _secret_to_seed( def _hmac( halg: hashes.HashAlgorithm, hmackey: bytes, enc_cred: bytes, name: bytes ) -> bytes: - h = HMAC(hmackey, halg(), backend=default_backend()) + h = HMAC(hmackey, halg(), backend=default_backend()) # type: ignore[operator] h.update(enc_cred) h.update(name) return h.finalize() @@ -618,7 +625,7 @@ def _check_hmac( name: bytes, expected: bytes, ): - h = HMAC(hmackey, halg(), backend=default_backend()) + h = HMAC(hmackey, halg(), backend=default_backend()) # type: ignore[operator] h.update(enc_cred) h.update(name) h.verify(expected) @@ -628,8 +635,8 @@ 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()) + ci = cipher(key) # type: ignore[call-arg] + ciph = Cipher(ci, mode(iv), backend=default_backend()) # type: ignore[call-arg] encr = ciph.encryptor() encdata = encr.update(data) + encr.finalize() return encdata @@ -639,8 +646,8 @@ 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()) + ci = cipher(key) # type: ignore[call-arg] + ciph = Cipher(ci, mode(iv), backend=default_backend()) # type: ignore[call-arg] decr = ciph.decryptor() plaintextdata = decr.update(data) + decr.finalize() return plaintextdata diff --git a/src/tpm2_pytss/internal/utils.py b/src/tpm2_pytss/internal/utils.py index 7f7ca0c6..6b58e0dd 100644 --- a/src/tpm2_pytss/internal/utils.py +++ b/src/tpm2_pytss/internal/utils.py @@ -1,15 +1,15 @@ # SPDX-License-Identifier: BSD-2 import logging import sys -from typing import List +from typing import List, Optional from packaging.version import Version, InvalidVersion -from .._libtpm2_pytss import ffi, lib # type: ignore +from .._libtpm2_pytss import ffi, lib # type: ignore[import] from ..TSS2_Exception import TSS2_Exception try: # This is generated by install, so just ignore it. - from .versions import _versions # type: ignore + from .versions import _versions # type: ignore[import] except ImportError as e: # this is needed so docs can be generated without building if "sphinx" not in sys.modules: @@ -200,7 +200,7 @@ def _check_friendly_int(friendly, varname, clazz): def is_bug_fixed( - fixed_in=None, backports: List[str] = None, lib: str = "tss2-fapi" + fixed_in=None, backports: Optional[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): @@ -227,7 +227,7 @@ def is_bug_fixed( def _check_bug_fixed( details, fixed_in=None, - backports: List[str] = None, + backports: Optional[List[str]] = None, lib: str = "tss2-fapi", error: bool = False, ) -> None: diff --git a/src/tpm2_pytss/policy.py b/src/tpm2_pytss/policy.py index 92ad3044..2867504a 100644 --- a/src/tpm2_pytss/policy.py +++ b/src/tpm2_pytss/policy.py @@ -18,7 +18,7 @@ ) from .constants import TPM2_ALG, ESYS_TR, TSS2_RC, TPM2_RC from .TSS2_Exception import TSS2_Exception -from ._libtpm2_pytss import ffi, lib # type: ignore +from ._libtpm2_pytss import ffi, lib # type: ignore[name-defined] from .ESAPI import ESAPI from enum import Enum from typing import Callable, Union diff --git a/src/tpm2_pytss/tsskey.py b/src/tpm2_pytss/tsskey.py index 9b31c72b..8bf1327d 100644 --- a/src/tpm2_pytss/tsskey.py +++ b/src/tpm2_pytss/tsskey.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2 import warnings -from ._libtpm2_pytss import lib # type: ignore +from ._libtpm2_pytss import lib # type: ignore[name-defined] from .types import * from .constants import TPM2_ECC, TPM2_CAP, ESYS_TR from asn1crypto.core import ObjectIdentifier, Sequence, Boolean, OctetString, Integer diff --git a/src/tpm2_pytss/types.py b/src/tpm2_pytss/types.py index 5c0a3c86..073abb4b 100644 --- a/src/tpm2_pytss/types.py +++ b/src/tpm2_pytss/types.py @@ -9,7 +9,7 @@ of key-value objects where the keys are the names of the associated type. """ -from ._libtpm2_pytss import ffi, lib # type: ignore +from ._libtpm2_pytss import ffi, lib # type: ignore[import] from tpm2_pytss.internal.utils import ( _chkrc, @@ -44,7 +44,7 @@ import sys try: - from tpm2_pytss.internal.type_mapping import _type_map, _element_type_map + from tpm2_pytss.internal.type_mapping import _type_map, _element_type_map # type: ignore[import] except ImportError as e: # this is needed so docs can be generated without building if "sphinx" not in sys.modules: @@ -845,7 +845,7 @@ def parse( TPMA_OBJECT, int, str ] = TPMA_OBJECT.DEFAULT_TPM2_TOOLS_CREATE_ATTRS, nameAlg: Union[TPM2_ALG, int, str] = "sha256", - authPolicy: bytes = None, + authPolicy: Optional[bytes] = None, ) -> "TPMT_PUBLIC": """Builds a TPMT_PUBLIC from a tpm2-tools like specifier strings. @@ -867,7 +867,8 @@ def parse( 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". + authPolicy (bytes): Optional, The policy digest of the object. This is tpm2-tools option "-L". + Defaults to None. Returns: A populated TPMT_PUBLIC for use. @@ -912,9 +913,9 @@ def parse( 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 + prefix_str = prefix[0] + keep_processing = getattr(TPMT_PUBLIC, f"_handle_{prefix_str}")( + objstr[len(prefix_str) :], templ ) else: raise ValueError( @@ -947,9 +948,9 @@ def from_pem( 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, + symmetric: Optional[TPMT_SYM_DEF_OBJECT] = None, + scheme: Optional[TPMT_ASYM_SCHEME] = None, + password: Optional[bytes] = None, ) -> "TPMT_PUBLIC": """Decode the public part from standard key encodings. @@ -1166,9 +1167,9 @@ def from_pem( 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, + symmetric: Optional[TPMT_SYM_DEF_OBJECT] = None, + scheme: Optional[TPMT_ASYM_SCHEME] = None, + password: Optional[bytes] = None, ) -> "TPM2B_PUBLIC": """Decode the public part from standard key encodings. @@ -1371,8 +1372,8 @@ def keyedhash_from_secret( objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), - scheme: TPMT_KEYEDHASH_SCHEME = None, - seed: bytes = None, + scheme: Optional[TPMT_KEYEDHASH_SCHEME] = None, + seed: Optional[bytes] = None, ) -> Tuple["TPM2B_SENSITIVE", TPM2B_PUBLIC]: """Generate the private and public part for a keyed hash object from a secret. @@ -1414,7 +1415,7 @@ def symcipher_from_secret( objectAttributes: Union[TPMA_OBJECT, int] = ( TPMA_OBJECT.DECRYPT | TPMA_OBJECT.SIGN_ENCRYPT | TPMA_OBJECT.USERWITHAUTH ), - seed: bytes = None, + seed: Optional[bytes] = None, ) -> Tuple["TPM2B_SENSITIVE", TPM2B_PUBLIC]: """Generate the private and public part for a symcipher object from a secret. @@ -1487,7 +1488,7 @@ def to_der(self, public: TPMT_PUBLIC) -> bytes: return self.sensitiveArea.to_der(public) - def to_ssh(self, public: TPMT_PUBLIC, password: bytes = None) -> bytes: + def to_ssh(self, public: TPMT_PUBLIC, password: Optional[bytes] = None) -> bytes: """Encode the key as OPENSSH PEM format. Args: @@ -1660,9 +1661,7 @@ def parse(selections: str) -> "TPML_PCR_SELECTION": f"got {len(selectors)}" ) - selections = [TPMS_PCR_SELECTION.parse(x) for x in selectors] - - return TPML_PCR_SELECTION(selections) + return TPML_PCR_SELECTION([TPMS_PCR_SELECTION.parse(x) for x in selectors]) class TPML_TAGGED_PCR_PROPERTY(TPML_OBJECT): @@ -1761,7 +1760,11 @@ def from_tools(cls, data: bytes) -> "TPMS_CONTEXT": ctx.contextBlob, _ = TPM2B_CONTEXT_DATA.unmarshal(data[24:]) return ctx - def to_tools(self, session_type: TPM2_SE = None, auth_hash: TPM2_ALG = None): + def to_tools( + self, + session_type: Optional[TPM2_SE] = None, + auth_hash: Optional[TPM2_ALG] = None, + ): """Marshal the context into a tpm2-tools context blob. Args: @@ -1794,8 +1797,9 @@ def to_tools(self, session_type: TPM2_SE = None, auth_hash: TPM2_ALG = None): 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") + # cannot hit "version 2" if session_type and auth_hash are None + data = data + session_type.to_bytes(1, "big") # type: ignore[union-attr] + data = data + auth_hash.to_bytes(2, "big") # type: ignore[union-attr] data = data + int(0xBADCC0DE).to_bytes(4, "big") + int(1).to_bytes(4, "big") data = data + self.hierarchy.to_bytes(4, "big") @@ -1926,13 +1930,13 @@ def parse(selection: str) -> "TPMS_PCR_SELECTION": if hunks[1] != "all": try: - pcrs = [int(x.strip(), 0) for x in hunks[1].split(",")] + return TPMS_PCR_SELECTION( + hash=halg, 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) + return TPMS_PCR_SELECTION(hash=halg, pcrs=hunks[1]) class TPMS_QUOTE_INFO(TPM_OBJECT): @@ -2154,10 +2158,10 @@ def symcipher_from_secret( def _serialize( self, - encoding: str, + encoding: serialization.Encoding, public: TPMT_PUBLIC, - format: str = serialization.PrivateFormat.TraditionalOpenSSL, - password: bytes = None, + format: serialization.PrivateFormat = serialization.PrivateFormat.TraditionalOpenSSL, + password: Optional[bytes] = None, ): k = private_to_key(self, public) @@ -2173,7 +2177,7 @@ def _serialize( return data - def to_pem(self, public: TPMT_PUBLIC, password: bytes = None): + def to_pem(self, public: TPMT_PUBLIC, password: Optional[bytes] = None): """Encode the key as PEM encoded ASN.1. public(TPMT_PUBLIC): The corresponding public key. @@ -2196,7 +2200,7 @@ def to_der(self, public: TPMT_PUBLIC): return self._serialize(serialization.Encoding.DER, public) - def to_ssh(self, public: TPMT_PUBLIC, password: bytes = None): + def to_ssh(self, public: TPMT_PUBLIC, password: Optional[bytes] = None): """Encode the key as SSH format. public(TPMT_PUBLIC): The corresponding public key. diff --git a/test/test_tsskey.py b/test/test_tsskey.py index e9e2e4db..b5448330 100644 --- a/test/test_tsskey.py +++ b/test/test_tsskey.py @@ -3,8 +3,8 @@ 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 # type: ignore -from asn1crypto import pem # type: ignore +from asn1crypto.core import ObjectIdentifier # type: ignore[name-defined] +from asn1crypto import pem # type: ignore[name-defined] import unittest