Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-tpm2-pytss for 
openSUSE:Factory checked in at 2024-10-09 22:12:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tpm2-pytss (Old)
 and      /work/SRC/openSUSE:Factory/.python-tpm2-pytss.new.19354 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-tpm2-pytss"

Wed Oct  9 22:12:46 2024 rev:6 rq:1206411 version:2.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tpm2-pytss/python-tpm2-pytss.changes      
2024-02-28 19:48:10.108098780 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-tpm2-pytss.new.19354/python-tpm2-pytss.changes
   2024-10-09 22:13:12.558910172 +0200
@@ -1,0 +2,18 @@
+Wed Oct  9 04:00:45 UTC 2024 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Update to version 2.3.0:
+  * FAPI: support exists_ok for create_nv
+  * Compatibility with python-cryptography 42
+  * scripts: update regex for #defines
+  * cryptography: fixes for newer version of cryptography
+  * docs/maintainers: add gpg key details
+  * docs: fix whitespace error
+  * docs: fix error on SECURITY.md not being used
+  * cryptography: add module for using TPM keys with the cryptography module
+  * encoding: add deprecation warning to tools_encdec
+  * internal/crypto: fix _MyRSAPrivateNumbers with cryptograpy >= 42.0.1
+  * test: disable pcr_set_auth_value and pcr_set_auth_policy tests for swtpm
+- Drop patch python-tpm2-pytss-RSAPrivateNumbers.patch, included upstream.
+- Switch to pyproject macros.
+
+-------------------------------------------------------------------

Old:
----
  python-tpm2-pytss-RSAPrivateNumbers.patch
  tpm2-pytss-2.2.0.tar.gz

New:
----
  tpm2-pytss-2.3.0.tar.gz

BETA DEBUG BEGIN:
  Old:  * test: disable pcr_set_auth_value and pcr_set_auth_policy tests for 
swtpm
- Drop patch python-tpm2-pytss-RSAPrivateNumbers.patch, included upstream.
- Switch to pyproject macros.
BETA DEBUG END:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-tpm2-pytss.spec ++++++
--- /var/tmp/diff_new_pack.cCZnQ1/_old  2024-10-09 22:13:13.410945696 +0200
+++ /var/tmp/diff_new_pack.cCZnQ1/_new  2024-10-09 22:13:13.410945696 +0200
@@ -17,28 +17,27 @@
 
 
 %define pythons python3
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define srcname tpm2-pytss
 %bcond_with     test
 Name:           python-%{srcname}
-Version:        2.2.0
+Version:        2.3.0
 Release:        0
 Summary:        Python bindings for TSS
 License:        BSD-2-Clause
 URL:            https://github.com/tpm2-software/tpm2-pytss
 Source:         %{srcname}-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM Fix tpm2-pkcs11 build: 
github.com/tpm2-software/tpm2-pytss/pull/562
-Patch0:         python-tpm2-pytss-RSAPrivateNumbers.patch
 BuildRequires:  %{python_module PyYAML}
 BuildRequires:  %{python_module asn1crypto}
 BuildRequires:  %{python_module cffi}
 BuildRequires:  %{python_module cryptography}
 BuildRequires:  %{python_module devel}
 BuildRequires:  %{python_module packaging}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module pkgconfig}
 BuildRequires:  %{python_module pycparser}
 BuildRequires:  %{python_module setuptools_scm}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  pkgconfig
 BuildRequires:  python-rpm-macros
@@ -49,7 +48,6 @@
 Requires:       python3-cffi
 Requires:       python3-cryptography
 Requires:       python3-packaging
-Requires:       python3-setuptools
 Requires:       pkgconfig(tss2-esys)
 Requires:       pkgconfig(tss2-fapi)
 %if %{with test}
@@ -81,10 +79,10 @@
 Version:        %{version}
 EOF
 export CFLAGS="%{optflags}"
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitearch}
 
 %if %{with test}
@@ -95,5 +93,5 @@
 %files %{python_files}
 %license LICENSE
 %{python_sitearch}/tpm2_pytss
-%{python_sitearch}/tpm2_pytss-%{version}*-info
+%{python_sitearch}/tpm2_pytss-%{version}.dist-info
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.cCZnQ1/_old  2024-10-09 22:13:13.438946864 +0200
+++ /var/tmp/diff_new_pack.cCZnQ1/_new  2024-10-09 22:13:13.442947030 +0200
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="disabled">
     <param name="filename">tpm2-pytss</param>
-    <param name="revision">2.2.0</param>
+    <param name="revision">2.3.0</param>
     <param name="scm">git</param>
     <param name="submodules">disable</param>
     <param name="url">https://github.com/tpm2-software/tpm2-pytss.git</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.cCZnQ1/_old  2024-10-09 22:13:13.462947865 +0200
+++ /var/tmp/diff_new_pack.cCZnQ1/_new  2024-10-09 22:13:13.466948031 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/tpm2-software/tpm2-pytss.git</param>
-              <param 
name="changesrevision">b9dae8373baad0f9f09a8d745a063f4960dd9369</param></service></servicedata>
+              <param 
name="changesrevision">930cee2c45b84ac533c320b883b226edaeda9a38</param></service></servicedata>
 (No newline at EOF)
 

++++++ tpm2-pytss-2.2.0.tar.gz -> tpm2-pytss-2.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/CHANGELOG.md 
new/tpm2-pytss-2.3.0/CHANGELOG.md
--- old/tpm2-pytss-2.2.0/CHANGELOG.md   2024-01-06 00:50:04.000000000 +0100
+++ new/tpm2-pytss-2.3.0/CHANGELOG.md   2024-06-27 10:36:21.000000000 +0200
@@ -4,6 +4,23 @@
 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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/docs/api.rst 
new/tpm2-pytss-2.3.0/docs/api.rst
--- old/tpm2-pytss-2.2.0/docs/api.rst   2024-01-06 00:50:04.000000000 +0100
+++ new/tpm2-pytss-2.3.0/docs/api.rst   2024-06-27 10:36:21.000000000 +0200
@@ -14,3 +14,4 @@
     Utility Routines <utils>
     TSS PEM Key (OpenSSL) <tsskey>
     TSS2_Exception <exception>
+    cryptography <cryptography>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/docs/cryptography.rst 
new/tpm2-pytss-2.3.0/docs/cryptography.rst
--- old/tpm2-pytss-2.2.0/docs/cryptography.rst  1970-01-01 01:00:00.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/docs/cryptography.rst  2024-06-27 10:36:21.000000000 
+0200
@@ -0,0 +1,6 @@
+cryptography
+============
+
+.. automodule:: tpm2_pytss.cryptography
+   :members:
+   :undoc-members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/docs/maintainers.rst 
new/tpm2-pytss-2.3.0/docs/maintainers.rst
--- old/tpm2-pytss-2.2.0/docs/maintainers.rst   2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/docs/maintainers.rst   2024-06-27 10:36:21.000000000 
+0200
@@ -3,5 +3,15 @@
 Project Maintainers
 -------------------
 
-- William Roberts <william.c.robe...@intel.com>
-- Erik Larsson <who+git...@cnackers.org>
+.. list-table:: Maintainers
+   :header-rows: 1
+
+   * - Name
+     - Email
+     - GPG Key Id
+   * - William Roberts
+     - bill.c.robe...@gmail.com
+     - D91A82DB310E8E07519C298A9877C26A3CD36409
+   * - Erik Larsson
+     - who+git...@cnackers.org
+     - 2CAF442B36D6D5D0EB82FBEA28630DB7CEE35E6F
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/docs/project.rst 
new/tpm2-pytss-2.3.0/docs/project.rst
--- old/tpm2-pytss-2.2.0/docs/project.rst       2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/docs/project.rst       2024-06-27 10:36:21.000000000 
+0200
@@ -7,7 +7,8 @@
     :maxdepth: 1
 
     Release Process <release>
-       Contributing <contributing>
+    Contributing <contributing>
     Maintainers <maintainers>
     Code of Conduct <CODE_OF_CONDUCT>
+    Security Practices <SECURITY>
     LICENSE <https://github.com/tpm2-software/tpm2-pytss/blob/master/LICENSE>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/scripts/prepare_headers.py 
new/tpm2-pytss-2.3.0/scripts/prepare_headers.py
--- old/tpm2-pytss-2.2.0/scripts/prepare_headers.py     2024-01-06 
00:50:04.000000000 +0100
+++ new/tpm2-pytss-2.3.0/scripts/prepare_headers.py     2024-06-27 
10:36:21.000000000 +0200
@@ -32,6 +32,7 @@
 
     # 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/src/tpm2_pytss/FAPI.py 
new/tpm2-pytss-2.3.0/src/tpm2_pytss/FAPI.py
--- old/tpm2-pytss-2.2.0/src/tpm2_pytss/FAPI.py 2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/src/tpm2_pytss/FAPI.py 2024-06-27 10:36:21.000000000 
+0200
@@ -1110,7 +1110,8 @@
         type_: Optional[Union[bytes, str]] = None,
         policy_path: Optional[Union[bytes, str]] = None,
         auth_value: Optional[Union[bytes, str]] = None,
-    ) -> None:
+        exists_ok: bool = False,
+    ) -> bool:
         """Create non-volatile (NV) storage on the TPM.
 
         Args:
@@ -1119,16 +1120,23 @@
             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)
+        _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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/src/tpm2_pytss/cryptography.py 
new/tpm2-pytss-2.3.0/src/tpm2_pytss/cryptography.py
--- old/tpm2-pytss-2.2.0/src/tpm2_pytss/cryptography.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/tpm2-pytss-2.3.0/src/tpm2_pytss/cryptography.py 2024-06-27 
10:36:21.000000000 +0200
@@ -0,0 +1,430 @@
+# 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()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/src/tpm2_pytss/encoding.py 
new/tpm2-pytss-2.3.0/src/tpm2_pytss/encoding.py
--- old/tpm2-pytss-2.2.0/src/tpm2_pytss/encoding.py     2024-01-06 
00:50:04.000000000 +0100
+++ new/tpm2-pytss-2.3.0/src/tpm2_pytss/encoding.py     2024-06-27 
10:36:21.000000000 +0200
@@ -80,6 +80,7 @@
 )
 import yaml
 import collections.abc
+import warnings
 
 
 class base_encdec(object):
@@ -825,6 +826,14 @@
     """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),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/src/tpm2_pytss/internal/crypto.py 
new/tpm2-pytss-2.3.0/src/tpm2_pytss/internal/crypto.py
--- old/tpm2-pytss-2.2.0/src/tpm2_pytss/internal/crypto.py      2024-01-06 
00:50:04.000000000 +0100
+++ new/tpm2-pytss-2.3.0/src/tpm2_pytss/internal/crypto.py      2024-06-27 
10:36:21.000000000 +0200
@@ -23,8 +23,9 @@
 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
 import secrets
+import inspect
 import sys
 
 _curvetable = (
@@ -84,6 +85,15 @@
     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:
@@ -220,7 +230,7 @@
     return key
 
 
-class _MyRSAPrivateNumbers(rsa.RSAPrivateNumbers):
+class _MyRSAPrivateNumbers:
     def __init__(self, p: int, n: int, e: int, pubnums: rsa.RSAPublicNumbers):
 
         q = n // p
@@ -231,7 +241,12 @@
         dmq1 = rsa.rsa_crt_dmq1(d, q)
         iqmp = rsa.rsa_crt_iqmp(p, q)
 
-        super().__init__(p, q, d, dmp1, dmq1, iqmp, pubnums)
+        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]:
@@ -251,15 +266,7 @@
     #
     @staticmethod
     def _modinv(a, m):
-
-        if sys.version_info < (3, 8):
-            g, x, y = _MyRSAPrivateNumbers._xgcd(a, m)
-            if g != 1:
-                raise Exception("modular inverse does not exist")
-            else:
-                return x % m
-        else:
-            return pow(a, -1, m)
+        return pow(a, -1, m)
 
     @staticmethod
     def _generate_d(p, q, e, n):
@@ -644,3 +651,60 @@
     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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_crypto.py 
new/tpm2-pytss-2.3.0/test/test_crypto.py
--- old/tpm2-pytss-2.2.0/test/test_crypto.py    2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/test/test_crypto.py    2024-06-27 10:36:21.000000000 
+0200
@@ -8,6 +8,7 @@
 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-----
@@ -206,7 +207,7 @@
         self._has_sect163r2 = True
         try:
             load_pem_public_key(ecc_bad_curve)
-        except ValueError:
+        except (ValueError, UnsupportedAlgorithm):
             self._has_sect163r2 = False
 
     def test_public_from_pem_rsa(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_cryptography.py 
new/tpm2-pytss-2.3.0/test/test_cryptography.py
--- old/tpm2-pytss-2.2.0/test/test_cryptography.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/tpm2-pytss-2.3.0/test/test_cryptography.py      2024-06-27 
10:36:21.000000000 +0200
@@ -0,0 +1,504 @@
+#!/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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_encoding.py 
new/tpm2-pytss-2.3.0/test/test_encoding.py
--- old/tpm2-pytss-2.2.0/test/test_encoding.py  2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/test/test_encoding.py  2024-06-27 10:36:21.000000000 
+0200
@@ -1406,7 +1406,7 @@
     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()
+        key = ec.generate_private_key(ec.SECP256R1()).public_key()
         kb = key.public_bytes(
             serialization.Encoding.PEM, 
serialization.PublicFormat.SubjectPublicKeyInfo
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_esapi.py 
new/tpm2-pytss-2.3.0/test/test_esapi.py
--- old/tpm2-pytss-2.2.0/test/test_esapi.py     2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/test/test_esapi.py     2024-06-27 10:36:21.000000000 
+0200
@@ -3585,6 +3585,8 @@
             self.ectx.pcr_allocate(pcrsels, session3=object())
 
     def test_pcr_set_auth_policy(self):
+        if getattr(self.tcti, "name", "") == "swtpm":
+            self.skipTest("pcr_set_auth_policy not supported by swtpm")
 
         policy = b"0123456789ABCDEF0123456789ABCDEF"
         self.ectx.pcr_set_auth_policy(policy, TPM2_ALG.SHA256, ESYS_TR.PCR20)
@@ -3630,6 +3632,8 @@
             )
 
     def test_pcr_set_auth_value(self):
+        if getattr(self.tcti, "name", "") == "swtpm":
+            self.skipTest("pcr_set_auth_value not supported by swtpm")
 
         self.ectx.pcr_set_auth_value(ESYS_TR.PCR20, b"password")
         self.ectx.tr_set_auth(ESYS_TR.PCR20, b"password")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_fapi.py 
new/tpm2-pytss-2.3.0/test/test_fapi.py
--- old/tpm2-pytss-2.2.0/test/test_fapi.py      2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/test/test_fapi.py      2024-06-27 10:36:21.000000000 
+0200
@@ -961,6 +961,22 @@
         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):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tpm2-pytss-2.2.0/test/test_policy.py 
new/tpm2-pytss-2.3.0/test/test_policy.py
--- old/tpm2-pytss-2.2.0/test/test_policy.py    2024-01-06 00:50:04.000000000 
+0100
+++ new/tpm2-pytss-2.3.0/test/test_policy.py    2024-06-27 10:36:21.000000000 
+0200
@@ -47,7 +47,7 @@
         super().setUp()
         self._has_secp192r1 = True
         try:
-            ec.generate_private_key(ec.SECP192R1)
+            ec.generate_private_key(ec.SECP192R1())
         except Exception:
             self._has_secp192r1 = False
 

Reply via email to