Skip to content

Commit

Permalink
Add documentation for the TPM 2.0 support
Browse files Browse the repository at this point in the history
Co-Authored-By: Amos Treiber <[email protected]>
  • Loading branch information
reneme and atreiber94 committed Oct 2, 2024
1 parent afcebe7 commit 0198e61
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 17 deletions.
10 changes: 10 additions & 0 deletions doc/api_ref/providers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ The TPM 1.2 standard is a specification for a hardware device which provides
cryptographic algorithms. Botan ships a :doc:`TPM provider <tpm>` for interacting
with TPM devices. It is disabled by default.

TPM 2.0
^^^^^^^^^^^^^

Botan ships a :doc:`TPM 2.0 provider <tpm>` for interacting with TPM 2.0 devices.
Access to the TPM is implemented via the TPM Software Stack (TSS) and is tested using
the open source `tpm2-tss implementation <https://github.com/tpm2-software/tpm2-tss>`__.
Botan allows to hook into the crypto callbacks of tpm2-tss (requires 4.0 or later) to
avoid pulling in another crypto library as a transitive dependency.
This provider is disabled by default.

CommonCrypto
^^^^^^^^^^^^^

Expand Down
6 changes: 3 additions & 3 deletions doc/api_ref/rng.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,10 @@ on POWER ``darn``. If the relevant instruction is not available, the
constructor of the class will throw at runtime. You can test
beforehand by checking the result of ``Processor_RNG::available()``.

TPM_RNG
^^^^^^^^^^^^^^^^^
TPM_RNG & TPM2_RNG
^^^^^^^^^^^^^^^^^^

This RNG type allows using the RNG exported from a TPM chip.
These RNG types allow using the RNG exported from a TPM chip.

PKCS11_RNG
^^^^^^^^^^^^^^^^^
Expand Down
249 changes: 243 additions & 6 deletions doc/api_ref/tpm.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Trusted Platform Module (TPM)
==========================================

.. versionadded:: 1.11.26

Some computers come with a TPM, which is a small side processor which can
perform certain operations which include RSA key generation and signing, a
random number generator, accessing a small amount of NVRAM, and a set of PCRs
Expand All @@ -11,10 +9,249 @@ authenticating a boot sequence).

The TPM NVRAM and PCR APIs are not supported by Botan at this time, patches welcome.

Currently only v1.2 TPMs are supported, and the only TPM library supported is
TrouSerS (http://trousers.sourceforge.net/). Hopefully both of these limitations
will be removed in a future release, in order to support newer TPM v2.0 systems.
The current code has been tested with an ST TPM running in a Lenovo laptop.
Currently, we support TPM v1.2 as well as v2.0 systems via independent wrappers
of TrouSerS (http://trousers.sourceforge.net/) for TPM v1.2 and tpm2-tss
(https://github.com/tpm2-software/tpm2-tss) for TPM v2.0. Note however that
the support for TPM v1.2 is deprecated as of Botan 3.5.0 and will be removed in
a future release.

TPM 2.0 Wrappers
----------------

.. versionadded:: 3.6.0

Botan's TPM v2.0 support is currently based on a wrapper of the tpm2-tss
library (https://github.com/tpm2-software/tpm2-tss). The code is tested in CI
against the swtpm simulator (https://github.com/stefanberger/swtpm).

Support for TPM v2.0 is provided by the ``tpm2`` module which is not built by
default as it requires an external dependency. Use the ``BOTAN_HAS_TPM2`` macro
to ensure that support for TPM v2.0 is available in your build of Botan.

The entire implementation is wrapped into the ``Botan::TPM2`` namespace. The
remainder of this section will omit the namespace prefix for brevity.

TPM 2.0 Context
~~~~~~~~~~~~~~~

The TPM context is the main entry point for all TPM operations. Also, it
provides authorative information about the TPM's capabilities and allows
persisting and evicting keys into the TPM's NVRAM.

.. cpp:class:: Botan::TPM2::Context

.. cpp:function:: std::shared_ptr<Context> create(const std::string& tcti)

Create a TPM2 context and connect to it via the given TPM Command
Transmission Interface (TCTI). The TCTI string is a colon-separated specifier
of the form ``tcti_name[:tcti_options=value,...]``.

.. cpp:function:: std::shared_ptr<Context> create(std::optional<std::string> tcti, std::optional<std::string> conf)

Create a TPM2 context and connect to it via the given TPM Command
Transmission Interface (TCTI). The configuration string is passed to the
TCTI. Both values may by empty, in which case the TPM-TSS2 will try to
determine them from default values.

.. cpp:function:: TPM2_HANDLE persist(TPM2::PrivateKey& key, const SessionBundle& sessions, std::span<const uint8_t> auth_value, std::optional<TPM2_HANDLE> persistent_handle)

Persists the given ``key`` in the TPM's NVRAM. The returned handle can be
used to load the key back into the TPM after a reboot. The ``auth_value``
is used to re-authenticate operations after transforming it to a persistent
key.

.. cpp:function:: void evict(std::unique_ptr<TPM2::PrivateKey> key, const SessionBundle& sessions)

Evicts the ``key`` from the TPM's NVRAM. The key must be a persistent key
and won't be available for any further use after the eviction. In particular
it won't be re-transformed into a transient key either.

.. cpp:function:: bool supports_botan_crypto_backend()

Returns whether the current configuration supports the Botan crypto backend.
This might return false if Botan was not built with the ``tpm2_crypto_backend``
enabled or the TPM2-TSS library is too old (3.x or older).

.. cpp:function:: void use_botan_crypto_backend(std::shared_ptr<Botan::RandomNumberGenerator> rng)

Enables the Botan crypto backend for this context. The RNG is needed to
generate key material for the communication with the TPM. It is crucial that
this RNG *does not* depend on the TPM for its entropy as this would create a
chicken-and-egg problem.

.. cpp:function:: bool supports_algorithm(std::string_view algo_name)

Returns whether the TPM supports the given algorithm. The ``algo_name`` is
the name of the algorithm as used in Botan. Eg. "RSA", "SHA-256", "AES-128",
"OAEP(SHA-256)", etc.

For further information about the functionality of the TPM context, please refer
to the doxygen comments in ``tpm2_context.h``.

TPM 2.0 Sessions
~~~~~~~~~~~~~~~~

TPM v2.0 uses sessions to authorize actions on the TPM, encrypt the
communication between the application and the TPM and perform audits of the
operations performed.

Botan provides a ``Session`` class to handle the creation of sessions and
comes with a ``SessionBundle`` helper to manage multiple sessions to be passed
to the TPM commands.

.. cpp:class:: Botan::TPM2::Session

.. cpp:function:: std::shared_ptr<Session> unauthenticated_session(const std::shared_ptr<Context>& ctx, std::string_view sym_algo, std::string_view hash_algo)

Creates an unauthenticated session, i.e. does not provide protection against
man-in-the-middle attacks by adversaries who can intercept and modify the
communication between the application and the TPM.

The ``sym_algo`` and ``hash_algo`` parameters specify the symmetric cipher
used to encrypt parameters flowing to and from the TPM and the hash of the
HMAC algorithm used to protect the integrity of the communication.

.. cpp:function:: std::shared_ptr<Session> authenticated_session(const std::shared_ptr<Context>& ctx, const PrivateKey& tpm_key, std::string_view sym_algo, std::string_view hash_algo)

Creates an authenticated session, i.e. it does provide protection against
man-in-the-middle attacks by adversaries who can intercept and modify the
communication between the application and the TPM, under the assumption that
the ``tpm_key`` is trustworthy and known only to the TPM.

The ``sym_algo`` and ``hash_algo`` parameters specify the symmetric cipher
used to encrypt parameters flowing to and from the TPM and the hash of the
HMAC algorithm used to protect the integrity of the communication.

Currently, there's no support for other TPM sessions.

TPM 2.0 Random Number Generator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``RandomNumberGenerator`` is an adapter to use the TPM's random number
generator as a source of entropy. It behaves exactly like any other RNG in
Botan.

.. cpp:class:: Botan::TPM2::RandomNumberGenerator

.. cpp:function:: RandomNumberGenerator(std::shared_ptr<Context> ctx, SessionBundle sessions)

Creates a new RNG object which uses the TPM's random number generator as a
source of entropy. The ``sessions`` parameter is a bundle of sessions to be
used for the RNG operations.

Asymmetric Keys hosted by a TPM 2.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The TPM v2.0 supports RSA and ECC keys. Botan provides the classed
``PrivateKey`` and ``PublicKey`` in the ``TPM2`` namespace, to manage and use
asymmetric keys on the TPM. Additionally there are derived classes for RSA. ECC
is not supported at this time, but could be added in the future.

Objects of these classes can be used throughout the Botan library to perform
cryptographic operations with TPM keys wherever an abstract
``Botan::Private_Key`` is expected.

.. cpp:class:: Botan::TPM2::PublicKey

.. cpp:function:: std::unique_ptr<Public_Key> load_persistent(const std::shared_ptr<Context>& ctx, TPM2_HANDLE persistent_object_handle, const SessionBundle& sessions)

Loads a public key that is persistent in the TPM's NVRAM given a
``persistent_object_handle``.

.. cpp:function:: std::unique_ptr<Public_Key> load_transient(const std::shared_ptr<Context>& ctx, std::span<const uint8_t> public_blob, const SessionBundle& sessions)

Loads a public key from the given ``public_blob`` which is essentially
a serialization of a public key returned from a TPM key pair creation.

.. cpp:function:: std::vector<uint8_t> raw_public_key_bits() const

Returns a serialized representation of the public key. This blob can be
loaded back into the TPM as a transient public key.

.. cpp:class:: Botan::TPM2::PrivateKey

.. cpp:function:: std::unique_ptr<Private_Key> load_persistent(const std::shared_ptr<Context>& ctx, TPM2_HANDLE persistent_object_handle, std::span<const uint8_t> auth_value, const SessionBundle& sessions)

Loads a private key that is persistent in the TPM's NVRAM given a
``persistent_object_handle`` and an ``auth_value`` (e.g. a password).

.. cpp:function:: std::unique_ptr<Private_Key> load_transient(const std::shared_ptr<Context>& ctx, std::span<const uint8_t> auth_value, const TPM2::PrivateKey& parent, std::span<const uint8_t> public_blob, std::span<const uint8_t> private_blob, const SessionBundle& sessions)

Loads a private key from the given ``public_blob`` and ``private_blob``
returned from a TPM key pair creation. To decipher the
``private_blob``, a ``parent`` key is needed (the same as the one used
to create the key). The ``auth_value`` is used to authenticate private
operations.

.. cpp:function:: std::unique_ptr<PrivateKey> create_transient_from_template(const std::shared_ptr<Context>& ctx, const SessionBundle& sessions, ESYS_TR parent, const TPMT_PUBLIC& key_template, const TPM2B_SENSITIVE_CREATE& sensitive_data);

Creates a new transient key pair on the TPM using the given
``key_template`` and ``sensitive_data`` under the given ``parent`` key.
This is a low-level function, and it assumes that the caller knows how
to create valid ``key_template`` and ``sensitive_data`` structures.
Typically, users should resort to using the creation functions in the
derived private key classes.

.. cpp:function:: secure_vector<uint8_t> raw_private_key_bits() const

Returns an encrypted "private blob" of the TPM private key if it is a
transient key. This blob can only be decrypted by the TPM that created
it when loading the key back into the TPM.

Botan provides a set of derived classes for RSA keys, which are used to create
and manage RSA keys on the TPM.

.. cpp:class:: Botan::TPM2::RSA_PrivateKey

.. cpp:function:: std::unique_ptr<TPM2::PrivateKey> create_unrestricted_transient(const std::shared_ptr<Context>& ctx, const SessionBundle& sessions, std::span<const uint8_t> auth_value, const TPM2::PrivateKey& parent, uint16_t keylength, std::optional<uint32_t> exponent);

Creates a new RSA key pair on the TPM with the given ``keylength`` and
an optional ``exponent``. Typical users should not specify the
exponent, as support for any but the default exponent (65537) is
optional in the TPM v2.0 specification.

Keys generated with this function are not restricted in their usage.
They may be used both for signing and data encryption with various
padding schemes. Furthermore, they are transient, i.e. they are not
stored in the TPM's NVRAM and must be loaded from their public and
private blobs after a reboot.

Once a transient key pair was created on the TPM, it can be persisted into the
TPM's NVRAM to make it available across reboots independently of the "private
blob". This is done by passing the key pair to the ``Context::persist`` method.

Botan as a TPM2-TSS Crypto Backend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The TPM2-TSS library (4.0 and later) provides a callback API to override its
default crypto backend (OpenSSL or mbedtls). Botan can optionally use this API
to provide a Botan-based crypto backend for TPM2-TSS and thus allowing to
avoid a dependency on another cryptographic library in applications.

Once a ``Context`` is created, the Botan-based crypto backend may be enabled for
it via the ``Context::use_botan_crypto_backend`` method. This will only succeed
if the method ``Context::supports_botan_crypto_backend`` returns true.

TPM 2.0 Example
~~~~~~~~~~~~~~~

The following example demonstrates how to create a TPM key pair and sign a
Certificate Signing Request (CSR) with it. This may be useful if one wants
to host a private key for TLS client authentication in a TPM, for example.

.. literalinclude:: /../src/examples/pkcs10_csr_on_tpm2.cpp
:language: cpp


TPM 1.2 Wrappers
----------------

.. versionadded:: 1.11.26

Currently v1.2 TPMs are supported via a wrapper of the TrouSerS
(http://trousers.sourceforge.net/) library. However, this wrapper is deprecated
and will be removed in a future release. The current code has been tested with
an ST TPM running in a Lenovo laptop.

Test for TPM support with the macro ``BOTAN_HAS_TPM``, include ``<botan/tpm.h>``.

Expand Down
11 changes: 9 additions & 2 deletions doc/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ by the user using
- ``--with-sqlite3`` enables using sqlite3 databases in various contexts
(TLS session cache, PSK database, etc).

- ``--with-tpm`` adds support for using TPM hardware via the TrouSerS library.
- ``--with-tpm`` adds support for TPM 1.2 hardware via the TrouSerS library.

- ``--with-tpm2`` adds support for TPM 2.0 hardware via the TSS2 library.

- ``--with-boost`` enables using some Boost libraries. In particular
Boost.Filesystem is used for a few operations (but on most platforms, a
Expand Down Expand Up @@ -1070,7 +1072,12 @@ Enable using sqlite3 for data storage
``--with-tpm``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Enable support for TPM
Enable support for TPM 1.2

``--with-tpm2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Enable support for TPM 2.0

``--program-suffix=SUFFIX``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
10 changes: 5 additions & 5 deletions doc/dev_ref/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,11 @@ need this functionality, and it can be done in the library for less than that,
then it makes sense to just write the code. Yup.

Currently the (optional) external dependencies of the library are several
compression libraries (zlib, bzip2, lzma), sqlite3 database, Trousers (TPM
integration), plus various operating system utilities like basic filesystem
operations. These provide major pieces of functionality which seem worth the
trouble of maintaining an integration with.
compression libraries (zlib, bzip2, lzma), sqlite3 database, Trousers (TPM 1.2
integration), TSS2 (TPM 2.0 integration) plus various operating system utilities
like basic filesystem operations. These provide major pieces of functionality
which seem worth the trouble of maintaining an integration with.

At this point the most plausible examples of an appropriate new external
dependency are all deeper integrations with system level cryptographic
interfaces (CommonCrypto, CryptoAPI, /dev/crypto, iOS keychain, TPM 2.0, etc)
interfaces (CommonCrypto, CryptoAPI, /dev/crypto, iOS keychain, etc)
1 change: 1 addition & 0 deletions doc/dev_ref/todo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ External Providers
* Windows CryptoNG provider (ciphers, hashes)
* Extend Apple CommonCrypto provider (HMAC, CMAC, RSA, ECDSA, ECDH)
* Add support for iOS keychain access
* Extend support for TPM 2.0 (ECC keys, PCR, NVRAM, Policies, etc)

TLS
----------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion readme.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Other Useful Things
----------------------------------------

* Full C++ PKCS #11 API wrapper
* Interfaces for TPM v1.2 device access
* Interfaces for TPM v1.2 and v2.0 device access
* Simple compression API wrapping zlib, bzip2, and lzma libraries
* RNG wrappers for system RNG and hardware RNGs
* HMAC_DRBG and entropy collection system for userspace RNGs
Expand Down
Loading

0 comments on commit 0198e61

Please sign in to comment.