Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TPM2 RNG #4117

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

Add TPM2 RNG #4117

wants to merge 14 commits into from

Conversation

atreiber94
Copy link
Collaborator

@atreiber94 atreiber94 commented Jun 12, 2024

This PR is for #3877 regarding the RNG integration of TPM2. It already includes FFI and Python integration.

For current progress on the entire TPM2 integration beyond RNG check #3877.

There's no need to merge this for 3.5.0 (this API may still possibly be subject to changes within broader TPM2 integration of #3877).

Setup with swtpm

To emulate the TPM2, we use swtpm. The following steps are necessary to setup swtpmto work with our implementation:

  1. Install tpm2-tools, libtss2-dev and swtpm: sudo apt install tpm2-tools libtss2-dev swtpm
  2. Configure Botan --with-tpm2 and build
  3. mkdir /tmp/myvtpm
  4. swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init (terminal has to stay open)
  5. tpm2_startup -c

By default, Botan's new TPM2_Context will use the TPM2-TSS default strategy for identifying the TCTI. To directly use swtpm or another TCTI, pass the corresponding TCTI name configuration to Botan::TPM2_Context::create.

Python example (because that's what we need)

import botan3 as botan
from binascii import hexlify

tpm2_ctx = botan.TPM2Context("swtpm")
tpm2_rng = botan.RandomNumberGenerator("tpm2", tpm2_ctx)

print(hexlify(tpm2_rng.get(32)).decode("utf-8"))

ToDos

  • CI Integration
  • Documentation

@atreiber94 atreiber94 added the enhancement Enhancement or new feature label Jun 12, 2024
@atreiber94 atreiber94 added this to the Botan 3.6.0 milestone Jun 12, 2024
@atreiber94 atreiber94 self-assigned this Jun 12, 2024
@coveralls
Copy link

Coverage Status

coverage: 91.777% (+0.002%) from 91.775%
when pulling bda3913 on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

@coveralls
Copy link

Coverage Status

coverage: 91.77% (-0.005%) from 91.775%
when pulling 9890bfa on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

@atreiber94 atreiber94 marked this pull request as ready for review June 12, 2024 15:23
BOTAN_ASSERT_NOMSG(digest->size == requested_bytes);
out.append({digest->buffer, digest->size});

Esys_Free(digest);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a good idea to use scoped_cleanup (or some variant of it) for this. Its unlikely, but if either the assert or the append above throw, the digest won't be freed.

#
class TPM2Context:
def __init__(self, tcti_nameconf: str = None) -> None:
tcti = c_char_p(0 if not tcti_nameconf else tcti_nameconf.encode("utf-8"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other locations (for instance the constructor of RandomNumberGenerator) use a _ctype_str() helper to transform a string object into a (presumable) const char*. Perhaps we should use that here as well? Let's look into it once more...


self.__obj = c_void_p(0)
rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj), tcti)
if rc == -40: # 'Not Implemented'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance we could pull this magic number from the enum? 😅
(there are other places that would benefit from it)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, though it seems like this is hard to do since we can't access the enum via CDLL. The other options of manually keeping the same enum in Python or providing functions that return respective enum values don't seem particularly worthwhile to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhh, there seems to be some secret sauce around the translation of parameter/result types from C to Python and back. This blog post provides a little inspiration: https://v4.chriskrycho.com/2015/ctypes-structures-and-dll-exports.html

Perhaps we could actually mirror the error-enum into botan3.py. That's a manual duplication, but should be okay, given that this enum probably doesn't change all the time. And then we could make CDLL do the translation for us.

Any of this should certainly not go into this pull request, though.

@randombit randombit self-requested a review June 12, 2024 22:35
}
}();

ctx->ctx = Botan::TPM2_Context::create(std::move(tcti));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an exception is throwing here due to for instance no hardware being available at runtime, the caller will get BOTAN_FFI_ERROR_EXCEPTION_THROWN which is not particularly helpful. Maybe catch this and then translate an error to something more specific?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe even just reusing BOTAN_FFI_ERROR_NOT_IMPLEMENTED if the hardware is unavailable? IDK

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I don't think reusing BOTAN_FFI_ERROR_NOT_IMPLEMENTED is all that helpful since the function would be implemented and TPM2 usage desired in that case (as the build is configured with --with-tpm2).

The exception that would be thrown here is TPM2_Error with error type ErrorType::TPMError. I added a corresponding FFI error type such that the caller will now get that error translated within ffi_guard_thunk instead of BOTAN_FFI_ERROR_EXCEPTION_THROWN. That way, one can distinguish between a runtime TPM error when configured with TPM and a not implemented error when TPM is not configured.

src/lib/prov/tpm2/tpm2.h Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2.cpp Show resolved Hide resolved

#include <tss2/tss2_esys.h>
#include <tss2/tss2_rc.h>
#include <tss2/tss2_tctildr.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing that most/all uses of TPM will just have a shared_ptr<TPM2_Context> that they invoke various functions from the library with. That being the case, if we could hide these few uses of the TPM2 types in this header, we likely could avoid pulling the TPM library includes into anything a user might include.

src/lib/prov/tpm2/tpm2.h Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2_rng.cpp Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2_rng.cpp Outdated Show resolved Hide resolved
@atreiber94
Copy link
Collaborator Author

atreiber94 commented Jun 13, 2024

Thanks for the comments! I applied review suggestions except the parts that require re-structuring tpm2.h, which I will pick up later on. As mentioned, we do not intend to merge this soon (not for 3.5.0)

@coveralls
Copy link

Coverage Status

coverage: 91.768% (-0.007%) from 91.775%
when pulling ed26467 on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

@@ -177,6 +177,10 @@ The following enum values are defined in the FFI header:
calling :cpp:func:`botan_hash_destroy` on a ``botan_rng_t`` object will cause
this error.

.. cpp:enumerator:: BOTAN_FFI_TPM_ERROR = -78
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. cpp:enumerator:: BOTAN_FFI_TPM_ERROR = -78
.. cpp:enumerator:: BOTAN_FFI_TPM2_ERROR = -78

... we've been specific basically everywhere. I think we should always state TPM2.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #4117 (comment) - this FFI error translates the ErrorType::TPMError, which is also the error type for TPM2_Error. Or should we just introduce a new TPM2 ErrorType and keep them separated entirely?

src/lib/prov/tpm2/tpm2.cpp Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2.h Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2.h Outdated Show resolved Hide resolved
src/lib/prov/tpm2/tpm2.h Show resolved Hide resolved
@coveralls
Copy link

Coverage Status

coverage: 91.763% (-0.01%) from 91.775%
when pulling 2ab6008 on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

@coveralls
Copy link

Coverage Status

coverage: 91.772% (-0.003%) from 91.775%
when pulling 70be246 on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

src/lib/prov/tpm2/tpm2.h Outdated Show resolved Hide resolved
…ntext_object() and add a helper function to safely cast to ESYS_CONTEXT*.
@coveralls
Copy link

Coverage Status

coverage: 91.731% (-0.04%) from 91.775%
when pulling 6e2af38 on Rohde-Schwarz:feature/tpm2
into 927aab8 on randombit:master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement or new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants