From 6109b2b17560ac0534a0097abf9d0863c9698ed1 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 10 Jun 2024 16:47:05 +0200 Subject: [PATCH 01/16] Add TPM2 Context and tpm2_rng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: René Meusel --- configure.py | 2 +- src/lib/prov/tpm2/info.txt | 23 ++++++++++ src/lib/prov/tpm2/tpm2.cpp | 49 ++++++++++++++++++++ src/lib/prov/tpm2/tpm2.h | 63 +++++++++++++++++++++++++ src/lib/prov/tpm2/tpm2_rng.cpp | 47 +++++++++++++++++++ src/lib/prov/tpm2/tpm2_rng.h | 36 +++++++++++++++ src/tests/test_tpm2.cpp | 84 ++++++++++++++++++++++++++++++++++ 7 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 src/lib/prov/tpm2/info.txt create mode 100644 src/lib/prov/tpm2/tpm2.cpp create mode 100644 src/lib/prov/tpm2/tpm2.h create mode 100644 src/lib/prov/tpm2/tpm2_rng.cpp create mode 100644 src/lib/prov/tpm2/tpm2_rng.h create mode 100644 src/tests/test_tpm2.cpp diff --git a/configure.py b/configure.py index 96a1c255573..d0787e975d3 100755 --- a/configure.py +++ b/configure.py @@ -580,7 +580,7 @@ def add_enable_disable_pair(group, what, default, msg=optparse.SUPPRESS_HELP): 'disable building of deprecated features and modules') # Should be derived from info.txt but this runs too early - third_party = ['boost', 'bzip2', 'lzma', 'commoncrypto', 'sqlite3', 'zlib', 'tpm'] + third_party = ['boost', 'bzip2', 'lzma', 'commoncrypto', 'sqlite3', 'zlib', 'tpm', 'tpm2'] for mod in third_party: mods_group.add_option('--with-%s' % (mod), diff --git a/src/lib/prov/tpm2/info.txt b/src/lib/prov/tpm2/info.txt new file mode 100644 index 00000000000..71519821b7d --- /dev/null +++ b/src/lib/prov/tpm2/info.txt @@ -0,0 +1,23 @@ + +TPM2 -> 20240610 + + + +name -> "TPM2" +brief -> "Wrappers and Utilites to interact with TPM2" + + +load_on vendor + + +all -> tss2-esys,tss2-rc + + + +rng + + + +tpm2.h +tpm2_rng.h + diff --git a/src/lib/prov/tpm2/tpm2.cpp b/src/lib/prov/tpm2/tpm2.cpp new file mode 100644 index 00000000000..3659375fc7d --- /dev/null +++ b/src/lib/prov/tpm2/tpm2.cpp @@ -0,0 +1,49 @@ +/* +* TPM 2 interface +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#include + +#include + +namespace Botan { + +TPM2_Error::TPM2_Error(std::string_view location, TSS2_RC rc) : + Exception(fmt("TPM2 Exception in {}: Code {} ({})", location, rc, Tss2_RC_Decode(rc))), m_rc(rc) {} + +std::string TPM2_Error::error_message() const { + return Tss2_RC_Decode(m_rc); +} + +std::shared_ptr TPM2_Context::create() { + return std::shared_ptr(new TPM2_Context()); +} + +TPM2_Context::TPM2_Context() { + check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_ctx, nullptr /* TCTI */, nullptr /* ABI version */)); +} + +TPM2_Context::TPM2_Context(TPM2_Context&& ctx) noexcept : m_ctx(ctx.m_ctx) { + ctx.m_ctx = nullptr; +} + +TPM2_Context& TPM2_Context::operator=(TPM2_Context&& ctx) noexcept { + if(this != &ctx) { + m_ctx = ctx.m_ctx; + ctx.m_ctx = nullptr; + } + + return *this; +} + +TPM2_Context::~TPM2_Context() { + Esys_Finalize(&m_ctx); +} + +} // namespace Botan diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h new file mode 100644 index 00000000000..115e01c9008 --- /dev/null +++ b/src/lib/prov/tpm2/tpm2.h @@ -0,0 +1,63 @@ +/* +* TPM 2 interface +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TPM2_H_ +#define BOTAN_TPM2_H_ + +#include + +#include +#include + +struct ESYS_CONTEXT; + +namespace Botan { + +class BOTAN_PUBLIC_API(3, 6) TPM2_Error final : public Exception { + public: + TPM2_Error(std::string_view location, TSS2_RC rc); + + ErrorType error_type() const noexcept override { return ErrorType::TPMError; } + + TSS2_RC code() const { return m_rc; } + + std::string error_message() const; + + private: + TSS2_RC m_rc; +}; + +inline void check_tss2_rc(std::string_view location, TSS2_RC rc) { + if(rc != TSS2_RC_SUCCESS) { + throw TPM2_Error(location, rc); + } +} + +class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { + public: + static std::shared_ptr create(); + + TPM2_Context(const TPM2_Context&) = delete; + TPM2_Context(TPM2_Context&& ctx) noexcept; + ~TPM2_Context(); + + TPM2_Context& operator=(const TPM2_Context&) = delete; + TPM2_Context& operator=(TPM2_Context&& ctx) noexcept; + + ESYS_CONTEXT* get() { return m_ctx; } + + private: + TPM2_Context(); + + private: + ESYS_CONTEXT* m_ctx; +}; + +} // namespace Botan + +#endif diff --git a/src/lib/prov/tpm2/tpm2_rng.cpp b/src/lib/prov/tpm2/tpm2_rng.cpp new file mode 100644 index 00000000000..8e12a9f7db2 --- /dev/null +++ b/src/lib/prov/tpm2/tpm2_rng.cpp @@ -0,0 +1,47 @@ +/* +* TPM 2 RNG interface +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#include + +#include +#include + +namespace Botan { + +namespace { +constexpr size_t MAX_STIR_RANDOM_SIZE = 128; // From specification of tpm2-tool's tpm2_stirrandom +} // anonymous namespace + +void TPM2_RNG::fill_bytes_with_input(std::span output, std::span input) { + BufferSlicer in(input); + BufferStuffer out(output); + + while(!in.empty()) { + TPM2B_SENSITIVE_DATA data; + data.size = std::min(in.remaining(), MAX_STIR_RANDOM_SIZE); + in.copy_into({data.buffer, data.size}); + + check_tss2_rc("StirRandom", Esys_StirRandom(m_ctx->get(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); + } + + while(!out.full()) { + TPM2B_DIGEST* digest = nullptr; + const auto requested_bytes = std::min(sizeof(digest->buffer), out.remaining_capacity()); + check_tss2_rc("GetRandom", + Esys_GetRandom(m_ctx->get(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, requested_bytes, &digest)); + + BOTAN_ASSERT_NOMSG(digest->size == requested_bytes); + out.append({digest->buffer, digest->size}); + + Esys_Free(digest); + } +} + +} // namespace Botan diff --git a/src/lib/prov/tpm2/tpm2_rng.h b/src/lib/prov/tpm2/tpm2_rng.h new file mode 100644 index 00000000000..cccd4fb1408 --- /dev/null +++ b/src/lib/prov/tpm2/tpm2_rng.h @@ -0,0 +1,36 @@ +/* +* TPM 2 RNG interface +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TPM2_RNG_H_ +#define BOTAN_TPM2_RNG_H_ + +#include + +#include + +namespace Botan { +class BOTAN_PUBLIC_API(3, 6) TPM2_RNG final : public Hardware_RNG { + public: + TPM2_RNG(std::shared_ptr ctx) : m_ctx(std::move(ctx)) {} + + bool accepts_input() const override { return true; } + + std::string name() const override { return "TPM2_RNG"; } + + bool is_seeded() const override { return true; } + + private: + void fill_bytes_with_input(std::span output, std::span input) override; + + private: + std::shared_ptr m_ctx; +}; + +} // namespace Botan + +#endif diff --git a/src/tests/test_tpm2.cpp b/src/tests/test_tpm2.cpp new file mode 100644 index 00000000000..ab390aa09d2 --- /dev/null +++ b/src/tests/test_tpm2.cpp @@ -0,0 +1,84 @@ +/* +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "tests.h" + +#include +#include + +#if defined(BOTAN_HAS_TPM2) + #include +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_TPM2) +namespace { + +bool not_zero_64(std::span in) { + Botan::BufferSlicer bs(in); + + while(bs.remaining() > 8) { + if(Botan::load_be(bs.take<8>()) == 0) { + return false; + } + } + // Ignore remaining bytes + + return true; +} + +std::vector test_tpm2_rng() { + auto ctx = Botan::TPM2_Context::create(); + + auto rng = Botan::TPM2_RNG(ctx); + + return { + Botan_Tests::CHECK("Basic functionalities", + [&](Test::Result& result) { + result.confirm("Accepts input", rng.accepts_input()); + result.confirm("Is seeded", rng.is_seeded()); + result.test_eq("Right name", rng.name(), "TPM2_RNG"); + + result.test_no_throw("Clear", [&] { rng.clear(); }); + }), + Botan_Tests::CHECK("Random number generation", + [&](Test::Result& result) { + std::array buf1 = {}; + rng.randomize(buf1); + result.confirm("Is at least not 0 (8)", not_zero_64(buf1)); + + std::array buf2 = {}; + rng.randomize(buf2); + result.confirm("Is at least not 0 (15)", not_zero_64(buf2)); + + std::array buf3 = {}; + rng.randomize(buf3); + result.confirm("Is at least not 0 (256)", not_zero_64(buf3)); + }), + + Botan_Tests::CHECK("Randomize with inputs", + [&](Test::Result& result) { + std::array buf1 = {}; + rng.randomize_with_input(buf1, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (9)", not_zero_64(buf1)); + + std::array buf2 = {}; + rng.randomize_with_input(buf2, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (66)", not_zero_64(buf2)); + + std::array buf3 = {}; + rng.randomize_with_input(buf3, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (256)", not_zero_64(buf3)); + }), + }; +} +} // namespace + +BOTAN_REGISTER_TEST_FN("tpm2", "tpm2_rng", test_tpm2_rng); +#endif + +} // namespace Botan_Tests From 52501317a2424ddf4eefba14df93289f0f52fec1 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Tue, 11 Jun 2024 15:02:31 +0200 Subject: [PATCH 02/16] Add FFI support for TPM2 RNG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: René Meusel --- src/lib/ffi/ffi.h | 26 +++++++++++++ src/lib/ffi/ffi_tpm2.cpp | 83 ++++++++++++++++++++++++++++++++++++++++ src/tests/test_ffi.cpp | 18 +++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/lib/ffi/ffi_tpm2.cpp diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index c0fd79f8b1a..636e0a887c6 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -259,6 +259,32 @@ BOTAN_FFI_EXPORT(2, 3) int botan_base64_decode(const char* base64_str, size_t in */ typedef struct botan_rng_struct* botan_rng_t; +/** +* TPM2 context +*/ +typedef struct botan_tpm2_ctx_struct* botan_tpm2_ctx_t; + +/** +* Initialize a TPM2 context +* @param ctx_out output TPM2 context +* @return 0 on success +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out); + +/** +* Frees all resouces of a TPM2 context +* @param ctx TPM2 context +* @return 0 on success +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx); + +/** +* Initialize a random number generator object via TPM2 +* @param rng_out rng object to create +* @param ctx TPM2 context +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx); + /** * Initialize a random number generator object * @param rng rng object diff --git a/src/lib/ffi/ffi_tpm2.cpp b/src/lib/ffi/ffi_tpm2.cpp new file mode 100644 index 00000000000..9a6a4ec0299 --- /dev/null +++ b/src/lib/ffi/ffi_tpm2.cpp @@ -0,0 +1,83 @@ +/* +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#include +#include + +#if defined(BOTAN_HAS_TPM2) + #include + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +/** + * This wrapper is required since BOTAN_FFI_DECLARE_STRUCT internally produces a unique pointer, + * but the TPM2_Context is meant to be used as a shared pointer. + */ +struct botan_tpm2_ctx_wrapper { + std::shared_ptr ctx; +}; + +#if defined(BOTAN_HAS_TPM2) +BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_ctx_struct, botan_tpm2_ctx_wrapper, 0xD2B95E15); +#endif + +int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out) { +#if defined(BOTAN_HAS_TPM2) + return ffi_guard_thunk(__func__, [=]() -> int { + if(ctx_out == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + auto ctx = std::make_unique(); + ctx->ctx = Botan::TPM2_Context::create(); + *ctx_out = new botan_tpm2_ctx_struct(std::move(ctx)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(rng, ctx); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + +#endif +} + +/** + * Frees all resouces of a TPM2 context + * @param ctx TPM2 context + * @return 0 on success + */ +int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx) { +#if defined(BOTAN_HAS_TPM2) + return BOTAN_FFI_CHECKED_DELETE(ctx); +#else + BOTAN_UNUSED(rng, ctx); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + +#endif +} + +int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx) { +#if defined(BOTAN_HAS_TPM2) + return BOTAN_FFI_VISIT(ctx, [=](botan_tpm2_ctx_wrapper& ctx_wrapper) -> int { + if(rng_out == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + *rng_out = new botan_rng_struct(std::make_unique(ctx_wrapper.ctx)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(rng, ctx); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + +#endif +} +} diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index d74c41500cb..90014cd14e8 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -277,6 +277,9 @@ class FFI_RNG_Test final : public FFI_Test { botan_rng_t hwrng_rng = nullptr; botan_rng_t null_rng; botan_rng_t custom_rng; + botan_rng_t tpm2_rng = nullptr; + + botan_tpm2_ctx_t tpm2_ctx; TEST_FFI_FAIL("invalid rng type", botan_rng_init, (&rng, "invalid_type")); @@ -363,10 +366,25 @@ class FFI_RNG_Test final : public FFI_Test { result.test_eq("custom_destroy_cb called", cb_counter, 5); } + if(TEST_FFI_INIT(botan_tpm2_ctx_init, (&tpm2_ctx))) { + if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_ctx))) { + Botan::clear_mem(outbuf.data(), outbuf.size()); + + TEST_FFI_OK(botan_rng_get, (tpm2_rng, outbuf.data(), outbuf.size())); + TEST_FFI_OK(botan_rng_reseed, (tpm2_rng, 256)); + + TEST_FFI_OK(botan_rng_reseed_from_rng, (tpm2_rng, system_rng, 256)); + + uint8_t not_really_entropy[32] = {0}; + TEST_FFI_OK(botan_rng_add_entropy, (tpm2_rng, not_really_entropy, 32)); + } + } + TEST_FFI_OK(botan_rng_destroy, (rng)); TEST_FFI_OK(botan_rng_destroy, (null_rng)); TEST_FFI_OK(botan_rng_destroy, (system_rng)); TEST_FFI_OK(botan_rng_destroy, (hwrng_rng)); + TEST_FFI_OK(botan_rng_destroy, (tpm2_rng)); } }; From e613f07d81280c89dfaf94fc66df681c9a587272 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 11:48:49 +0200 Subject: [PATCH 03/16] Add TPM2 RNG support for Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: René Meusel --- src/lib/ffi/ffi_tpm2.cpp | 8 ++++---- src/python/botan3.py | 31 +++++++++++++++++++++++++++++-- src/scripts/test_python.py | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/lib/ffi/ffi_tpm2.cpp b/src/lib/ffi/ffi_tpm2.cpp index 9a6a4ec0299..940c06c5bda 100644 --- a/src/lib/ffi/ffi_tpm2.cpp +++ b/src/lib/ffi/ffi_tpm2.cpp @@ -19,6 +19,7 @@ extern "C" { using namespace Botan_FFI; +#if defined(BOTAN_HAS_TPM2) /** * This wrapper is required since BOTAN_FFI_DECLARE_STRUCT internally produces a unique pointer, * but the TPM2_Context is meant to be used as a shared pointer. @@ -27,7 +28,6 @@ struct botan_tpm2_ctx_wrapper { std::shared_ptr ctx; }; -#if defined(BOTAN_HAS_TPM2) BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_ctx_struct, botan_tpm2_ctx_wrapper, 0xD2B95E15); #endif @@ -43,7 +43,7 @@ int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out) { return BOTAN_FFI_SUCCESS; }); #else - BOTAN_UNUSED(rng, ctx); + BOTAN_UNUSED(ctx_out); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif @@ -58,7 +58,7 @@ int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx) { #if defined(BOTAN_HAS_TPM2) return BOTAN_FFI_CHECKED_DELETE(ctx); #else - BOTAN_UNUSED(rng, ctx); + BOTAN_UNUSED(ctx); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif @@ -75,7 +75,7 @@ int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx) { return BOTAN_FFI_SUCCESS; }); #else - BOTAN_UNUSED(rng, ctx); + BOTAN_UNUSED(rng_out, ctx); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif diff --git a/src/python/botan3.py b/src/python/botan3.py index 9c75b31e494..0c21c522f5d 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -6,6 +6,7 @@ (C) 2015,2017,2018,2019,2023 Jack Lloyd (C) 2015 Uri Blumenthal (extensions and patches) +(C) 2024 Amos Treiber, René Meusel - Rohde & Schwarz Cybersecurity Botan is released under the Simplified BSD License (see license.txt) @@ -502,6 +503,11 @@ def ffi_api(fn, args, allowed_errors=None): ffi_api(dll.botan_zfec_decode, [c_size_t, c_size_t, POINTER(c_size_t), POINTER(c_char_p), c_size_t, POINTER(c_char_p)]) + # TPM2 + ffi_api(dll.botan_tpm2_ctx_init, [c_void_p], [-40]) + ffi_api(dll.botan_tpm2_ctx_destroy, [c_void_p], [-40]) + ffi_api(dll.botan_tpm2_rng_init, [c_void_p, c_void_p]) + return dll # @@ -636,9 +642,14 @@ def const_time_compare(x, y): # class RandomNumberGenerator: # Can also use type "system" - def __init__(self, rng_type='system'): + def __init__(self, rng_type='system', ctx=None): self.__obj = c_void_p(0) - _DLL.botan_rng_init(byref(self.__obj), _ctype_str(rng_type)) + if rng_type == 'tpm2': + if not isinstance(ctx, TPM2_Context): + raise BotanException("Cannot instantiate a TPM2-based RNG without a TPM2 context") + _DLL.botan_tpm2_rng_init(byref(self.__obj), ctx.handle_()) + else: + _DLL.botan_rng_init(byref(self.__obj), _ctype_str(rng_type)) def __del__(self): _DLL.botan_rng_destroy(self.__obj) @@ -2138,3 +2149,19 @@ def zfec_decode(k, n, indexes, inputs): c_size_t(k), c_size_t(n), c_indexes, c_inputs, c_size_t(share_size), c_outputs ) return [output.raw for output in outputs] + +# +# TPM2 +# +class TPM2_Context: + def __init__(self) -> None: + self.__obj = c_void_p(0) + rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj)) + if rc == -40: # 'Not Implemented' + raise BotanException("TPM2 is not implemented in this build configuration", rc) + + def __del__(self) -> None: + _DLL.botan_tpm2_ctx_destroy(self.__obj) + + def handle_(self): + return self.__obj diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index e13155051ec..3f548ae565c 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -176,6 +176,25 @@ def test_rng(self): user_rng.add_entropy('seed material...') + def test_tpm2_rng(self): + try: + tpm2_ctx = botan.TPM2_Context() + except botan.BotanException as ex: + if ex.error_code() == -40: # Not Implemented + self.skipTest("No TPM2 support in this build") + else: + raise ex + + tpm2_rng = botan.RandomNumberGenerator("tpm2", tpm2_ctx) + + output1 = tpm2_rng.get(32) + output2 = tpm2_rng.get(32) + + self.assertEqual(len(output1), 32) + self.assertEqual(len(output2), 32) + self.assertNotEqual(output1, output2) + tpm2_rng.add_entropy('xkcd #221: 4 - chosen by fair dice roll') + def test_hash(self): try: From c2058588af6afbfd7393960ffa27f72ecd3dec80 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 14:31:07 +0200 Subject: [PATCH 04/16] Include TCTI configuration into TPM2_Context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: René Meusel --- src/lib/ffi/ffi.h | 3 ++- src/lib/ffi/ffi_tpm2.cpp | 16 +++++++++++----- src/lib/prov/tpm2/info.txt | 2 +- src/lib/prov/tpm2/tpm2.cpp | 18 ++++++++++++++---- src/lib/prov/tpm2/tpm2.h | 16 +++++++++++----- src/python/botan3.py | 8 +++++--- src/scripts/test_python.py | 3 ++- src/tests/test_ffi.cpp | 3 ++- src/tests/test_tpm2.cpp | 3 ++- 9 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 636e0a887c6..7e5b6736a66 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -267,9 +267,10 @@ typedef struct botan_tpm2_ctx_struct* botan_tpm2_ctx_t; /** * Initialize a TPM2 context * @param ctx_out output TPM2 context +* @param tcti_nameconf TCTI config (may be nullpointer) * @return 0 on success */ -BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out); +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf); /** * Frees all resouces of a TPM2 context diff --git a/src/lib/ffi/ffi_tpm2.cpp b/src/lib/ffi/ffi_tpm2.cpp index 940c06c5bda..8317818b244 100644 --- a/src/lib/ffi/ffi_tpm2.cpp +++ b/src/lib/ffi/ffi_tpm2.cpp @@ -31,21 +31,29 @@ struct botan_tpm2_ctx_wrapper { BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_ctx_struct, botan_tpm2_ctx_wrapper, 0xD2B95E15); #endif -int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out) { +int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf) { #if defined(BOTAN_HAS_TPM2) return ffi_guard_thunk(__func__, [=]() -> int { if(ctx_out == nullptr) { return BOTAN_FFI_ERROR_NULL_POINTER; } auto ctx = std::make_unique(); - ctx->ctx = Botan::TPM2_Context::create(); + + auto tcti = [=]() -> std::optional { + if(tcti_nameconf == nullptr) { + return {}; + } else { + return std::string(tcti_nameconf); + } + }(); + + ctx->ctx = Botan::TPM2_Context::create(std::move(tcti)); *ctx_out = new botan_tpm2_ctx_struct(std::move(ctx)); return BOTAN_FFI_SUCCESS; }); #else BOTAN_UNUSED(ctx_out); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; - #endif } @@ -60,7 +68,6 @@ int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx) { #else BOTAN_UNUSED(ctx); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; - #endif } @@ -77,7 +84,6 @@ int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx) { #else BOTAN_UNUSED(rng_out, ctx); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; - #endif } } diff --git a/src/lib/prov/tpm2/info.txt b/src/lib/prov/tpm2/info.txt index 71519821b7d..a1487d75fb6 100644 --- a/src/lib/prov/tpm2/info.txt +++ b/src/lib/prov/tpm2/info.txt @@ -10,7 +10,7 @@ brief -> "Wrappers and Utilites to interact with TPM2" load_on vendor -all -> tss2-esys,tss2-rc +all -> tss2-esys,tss2-rc,tss2-tctildr diff --git a/src/lib/prov/tpm2/tpm2.cpp b/src/lib/prov/tpm2/tpm2.cpp index 3659375fc7d..f1ce599491a 100644 --- a/src/lib/prov/tpm2/tpm2.cpp +++ b/src/lib/prov/tpm2/tpm2.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace Botan { @@ -21,12 +22,20 @@ std::string TPM2_Error::error_message() const { return Tss2_RC_Decode(m_rc); } -std::shared_ptr TPM2_Context::create() { - return std::shared_ptr(new TPM2_Context()); +std::shared_ptr TPM2_Context::create(std::optional tcti_nameconf) { + const auto tcti_nameconf_ptr = [&]() -> const char* { + if(tcti_nameconf.has_value()) { + return tcti_nameconf->c_str(); + } else { + return nullptr; + } + }(); + return std::shared_ptr(new TPM2_Context(tcti_nameconf_ptr)); } -TPM2_Context::TPM2_Context() { - check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_ctx, nullptr /* TCTI */, nullptr /* ABI version */)); +TPM2_Context::TPM2_Context(const char* tcti_nameconf) { + check_tss2_rc("TCTI Initialization", Tss2_TctiLdr_Initialize(tcti_nameconf, &m_tcti_ctx)); + check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_ctx, m_tcti_ctx, nullptr /* ABI version */)); } TPM2_Context::TPM2_Context(TPM2_Context&& ctx) noexcept : m_ctx(ctx.m_ctx) { @@ -44,6 +53,7 @@ TPM2_Context& TPM2_Context::operator=(TPM2_Context&& ctx) noexcept { TPM2_Context::~TPM2_Context() { Esys_Finalize(&m_ctx); + Tss2_TctiLdr_Finalize(&m_tcti_ctx); } } // namespace Botan diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h index 115e01c9008..ed26d2cda0c 100644 --- a/src/lib/prov/tpm2/tpm2.h +++ b/src/lib/prov/tpm2/tpm2.h @@ -12,12 +12,13 @@ #include #include -#include +#include -struct ESYS_CONTEXT; +#include +#include +#include namespace Botan { - class BOTAN_PUBLIC_API(3, 6) TPM2_Error final : public Exception { public: TPM2_Error(std::string_view location, TSS2_RC rc); @@ -40,7 +41,11 @@ inline void check_tss2_rc(std::string_view location, TSS2_RC rc) { class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { public: - static std::shared_ptr create(); + /** + * @param tcti_nameconf if set this is passed to Tss2_TctiLdr_Initialize verbatim + * otherwise a nullptr is passed. + */ + static std::shared_ptr create(std::optional tcti_nameconf = {}); TPM2_Context(const TPM2_Context&) = delete; TPM2_Context(TPM2_Context&& ctx) noexcept; @@ -52,9 +57,10 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { ESYS_CONTEXT* get() { return m_ctx; } private: - TPM2_Context(); + TPM2_Context(const char* tcti_nameconf); private: + TSS2_TCTI_CONTEXT* m_tcti_ctx; ESYS_CONTEXT* m_ctx; }; diff --git a/src/python/botan3.py b/src/python/botan3.py index 0c21c522f5d..6d19937932e 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -504,7 +504,7 @@ def ffi_api(fn, args, allowed_errors=None): [c_size_t, c_size_t, POINTER(c_size_t), POINTER(c_char_p), c_size_t, POINTER(c_char_p)]) # TPM2 - ffi_api(dll.botan_tpm2_ctx_init, [c_void_p], [-40]) + ffi_api(dll.botan_tpm2_ctx_init, [c_void_p, c_char_p], [-40]) ffi_api(dll.botan_tpm2_ctx_destroy, [c_void_p], [-40]) ffi_api(dll.botan_tpm2_rng_init, [c_void_p, c_void_p]) @@ -2154,9 +2154,11 @@ def zfec_decode(k, n, indexes, inputs): # TPM2 # class TPM2_Context: - def __init__(self) -> None: + def __init__(self, tcti_nameconf: str = None) -> None: + tcti = c_char_p(0 if not tcti_nameconf else tcti_nameconf.encode("utf-8")) + self.__obj = c_void_p(0) - rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj)) + rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj), tcti) if rc == -40: # 'Not Implemented' raise BotanException("TPM2 is not implemented in this build configuration", rc) diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index 3f548ae565c..067ac2a76fd 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -178,7 +178,8 @@ def test_rng(self): def test_tpm2_rng(self): try: - tpm2_ctx = botan.TPM2_Context() + use_tpm2_emulator = "swtpm" + tpm2_ctx = botan.TPM2_Context(use_tpm2_emulator) except botan.BotanException as ex: if ex.error_code() == -40: # Not Implemented self.skipTest("No TPM2 support in this build") diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 90014cd14e8..6f1de9a3c54 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -366,7 +366,8 @@ class FFI_RNG_Test final : public FFI_Test { result.test_eq("custom_destroy_cb called", cb_counter, 5); } - if(TEST_FFI_INIT(botan_tpm2_ctx_init, (&tpm2_ctx))) { + const auto use_tpm2_emulator = "swtpm"; + if(TEST_FFI_INIT(botan_tpm2_ctx_init, (&tpm2_ctx, use_tpm2_emulator))) { if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_ctx))) { Botan::clear_mem(outbuf.data(), outbuf.size()); diff --git a/src/tests/test_tpm2.cpp b/src/tests/test_tpm2.cpp index ab390aa09d2..184025d0c28 100644 --- a/src/tests/test_tpm2.cpp +++ b/src/tests/test_tpm2.cpp @@ -32,7 +32,8 @@ bool not_zero_64(std::span in) { } std::vector test_tpm2_rng() { - auto ctx = Botan::TPM2_Context::create(); + std::string use_tpm2_emulator = "swtpm"; + auto ctx = Botan::TPM2_Context::create(std::move(use_tpm2_emulator)); auto rng = Botan::TPM2_RNG(ctx); From bda3913d2cfb56b8e98a7165acd6c5aef550b9b1 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 14:57:18 +0200 Subject: [PATCH 05/16] Fix CI --- src/lib/ffi/ffi_tpm2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ffi/ffi_tpm2.cpp b/src/lib/ffi/ffi_tpm2.cpp index 8317818b244..7c65f345434 100644 --- a/src/lib/ffi/ffi_tpm2.cpp +++ b/src/lib/ffi/ffi_tpm2.cpp @@ -52,7 +52,7 @@ int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf) { return BOTAN_FFI_SUCCESS; }); #else - BOTAN_UNUSED(ctx_out); + BOTAN_UNUSED(ctx_out, tcti_nameconf); return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } From 78f1bee63fd9179901a12487b7a08683714788e5 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 15:28:03 +0200 Subject: [PATCH 06/16] Fix Python linting issues --- src/python/botan3.py | 2 +- src/scripts/test_python.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/botan3.py b/src/python/botan3.py index 6d19937932e..1f1595a86b6 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -2153,7 +2153,7 @@ def zfec_decode(k, n, indexes, inputs): # # TPM2 # -class TPM2_Context: +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")) diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index 067ac2a76fd..034b87ff4e3 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -179,7 +179,7 @@ def test_rng(self): def test_tpm2_rng(self): try: use_tpm2_emulator = "swtpm" - tpm2_ctx = botan.TPM2_Context(use_tpm2_emulator) + tpm2_ctx = botan.TPM2Context(use_tpm2_emulator) except botan.BotanException as ex: if ex.error_code() == -40: # Not Implemented self.skipTest("No TPM2 support in this build") From 1cd900b1b0a6e056535aa5c5dc93b475e8f571f7 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 15:36:40 +0200 Subject: [PATCH 07/16] Add CI support for TPM2/swtpm --- src/scripts/ci/setup_gh_actions.sh | 7 ++++++- src/scripts/ci_build.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scripts/ci/setup_gh_actions.sh b/src/scripts/ci/setup_gh_actions.sh index d4c96a566d5..527d010f0e0 100755 --- a/src/scripts/ci/setup_gh_actions.sh +++ b/src/scripts/ci/setup_gh_actions.sh @@ -82,7 +82,7 @@ if type -p "apt-get"; then curl -L https://coveralls.io/coveralls-linux.tar.gz | tar -xz -C /usr/local/bin fi - sudo apt-get -qq install softhsm2 libtspi-dev libboost-dev + sudo apt-get -qq install softhsm2 libtspi-dev libboost-dev tpm2-tools libtss2-dev swtpm echo "$HOME/.local/bin" >> "$GITHUB_PATH" @@ -92,6 +92,11 @@ if type -p "apt-get"; then softhsm2-util --init-token --free --label test --pin 123456 --so-pin 12345678 echo "PKCS11_LIB=/usr/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV" + tpm2_state="/tmp/swtpm2" + mkdir $tpm2_state + swtpm socket --tpmstate dir=$tpm2_state --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init --daemon + tpm2_startup --tcti swtpm --clear + elif [ "$TARGET" = "docs" ]; then sudo apt-get -qq install doxygen python3-docutils python3-sphinx diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py index 539799716e5..662b2a9b27b 100755 --- a/src/scripts/ci_build.py +++ b/src/scripts/ci_build.py @@ -395,7 +395,7 @@ def add_boost_support(target, target_os): flags += ['--with-lzma'] if target in ['coverage']: - flags += ['--with-tpm'] + flags += ['--with-tpm', '--with-tpm2'] test_cmd += ['--run-online-tests'] if pkcs11_lib and os.access(pkcs11_lib, os.R_OK): test_cmd += ['--pkcs11-lib=%s' % (pkcs11_lib)] From c6a3a02b42524cdd5a00c0a52600b55cde6fd9e2 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 16:05:23 +0200 Subject: [PATCH 08/16] Fix TPM2_Context vs TPm2Context in botan3.py --- src/python/botan3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/botan3.py b/src/python/botan3.py index 1f1595a86b6..4d135fe891b 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -645,7 +645,7 @@ class RandomNumberGenerator: def __init__(self, rng_type='system', ctx=None): self.__obj = c_void_p(0) if rng_type == 'tpm2': - if not isinstance(ctx, TPM2_Context): + if not isinstance(ctx, TPM2Context): raise BotanException("Cannot instantiate a TPM2-based RNG without a TPM2 context") _DLL.botan_tpm2_rng_init(byref(self.__obj), ctx.handle_()) else: From d1244e3c284f6bdd3935019f914fa578d1874331 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 16:24:25 +0200 Subject: [PATCH 09/16] Extend CI for TPM2 --- src/scripts/ci/setup_gh_actions.sh | 18 +++++++++++++----- src/scripts/ci_build.py | 4 +++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/scripts/ci/setup_gh_actions.sh b/src/scripts/ci/setup_gh_actions.sh index 527d010f0e0..2d0b4ccb6c4 100755 --- a/src/scripts/ci/setup_gh_actions.sh +++ b/src/scripts/ci/setup_gh_actions.sh @@ -16,6 +16,13 @@ ARCH="$2" SCRIPT_LOCATION=$(cd "$(dirname "$0")"; pwd) +start_swtpm() { + tpm2_state="/tmp/swtpm2" + mkdir $tpm2_state + swtpm socket --tpmstate dir=$tpm2_state --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init --daemon + tpm2_startup --tcti swtpm --clear +} + if type -p "apt-get"; then if [ "$(lsb_release -sr)" = "22.04" ]; then @@ -33,7 +40,11 @@ if type -p "apt-get"; then # (l)ist mode (avoiding https://github.com/actions/runner-images/issues/9996) sudo NEEDRESTART_MODE=l apt-get -qq install valgrind - elif [ "$TARGET" = "shared" ] || [ "$TARGET" = "examples" ] || [ "$TARGET" = "tlsanvil" ] || [ "$TARGET" = "clang-tidy" ] ; then + elif [ "$TARGET" = "shared" ]; then + sudo apt-get -qq install libboost-dev tpm2-tools libtss2-dev swtpm + start_swtpm + + elif [ "$TARGET" = "examples" ] || [ "$TARGET" = "tlsanvil" ] || [ "$TARGET" = "clang-tidy" ] ; then sudo apt-get -qq install libboost-dev elif [ "$TARGET" = "clang" ]; then @@ -92,10 +103,7 @@ if type -p "apt-get"; then softhsm2-util --init-token --free --label test --pin 123456 --so-pin 12345678 echo "PKCS11_LIB=/usr/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV" - tpm2_state="/tmp/swtpm2" - mkdir $tpm2_state - swtpm socket --tpmstate dir=$tpm2_state --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init --daemon - tpm2_startup --tcti swtpm --clear + start_swtpm elif [ "$TARGET" = "docs" ]; then sudo apt-get -qq install doxygen python3-docutils python3-sphinx diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py index 662b2a9b27b..de0a4b5c748 100755 --- a/src/scripts/ci_build.py +++ b/src/scripts/ci_build.py @@ -393,9 +393,11 @@ def add_boost_support(target, target_os): if target_os == 'linux': flags += ['--with-lzma'] + if target in ['coverage', 'sanitizer', 'shared']: + flags += ['--with-tpm2'] if target in ['coverage']: - flags += ['--with-tpm', '--with-tpm2'] + flags += ['--with-tpm'] test_cmd += ['--run-online-tests'] if pkcs11_lib and os.access(pkcs11_lib, os.R_OK): test_cmd += ['--pkcs11-lib=%s' % (pkcs11_lib)] From 9890bfa1b0e80f0f07418ad7323b46e964e79dea Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Wed, 12 Jun 2024 16:42:15 +0200 Subject: [PATCH 10/16] Fix Memory Leak in C FFI Test --- src/tests/test_ffi.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 6f1de9a3c54..4405f546ae6 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -379,6 +379,8 @@ class FFI_RNG_Test final : public FFI_Test { uint8_t not_really_entropy[32] = {0}; TEST_FFI_OK(botan_rng_add_entropy, (tpm2_rng, not_really_entropy, 32)); } + + TEST_FFI_OK(botan_tpm2_ctx_destroy, (tpm2_ctx)); } TEST_FFI_OK(botan_rng_destroy, (rng)); From ed26467c1f2d2fe1d6b3fe943a45f8a3fd79066b Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Thu, 13 Jun 2024 16:43:39 +0200 Subject: [PATCH 11/16] Apply review suggestions except tpm2.h restructuring --- doc/api_ref/ffi.rst | 4 ++++ src/lib/ffi/ffi.cpp | 4 +++- src/lib/ffi/ffi.h | 1 + src/lib/prov/tpm2/tpm2.h | 5 +++++ src/lib/prov/tpm2/tpm2_rng.cpp | 13 ++++++------- src/python/botan3.py | 4 +--- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/doc/api_ref/ffi.rst b/doc/api_ref/ffi.rst index e4309b0d88b..c83bbd3318a 100644 --- a/doc/api_ref/ffi.rst +++ b/doc/api_ref/ffi.rst @@ -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 + + An error occured when performing TPM2 interactions. + .. cpp:enumerator:: BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100 Something bad happened, but we are not sure why or how. diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 2fe79ce1c3d..78135cea1f1 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -67,13 +67,15 @@ int ffi_map_error_type(Botan::ErrorType err) { case Botan::ErrorType::IoError: case Botan::ErrorType::Pkcs11Error: case Botan::ErrorType::CommonCryptoError: - case Botan::ErrorType::TPMError: case Botan::ErrorType::ZlibError: case Botan::ErrorType::Bzip2Error: case Botan::ErrorType::LzmaError: case Botan::ErrorType::DatabaseError: return BOTAN_FFI_ERROR_SYSTEM_ERROR; + case Botan::ErrorType::TPMError: + return BOTAN_FFI_ERROR_TPM_ERROR; + case Botan::ErrorType::NotImplemented: return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; case Botan::ErrorType::OutOfMemory: diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 7e5b6736a66..f6ff58ad86e 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -127,6 +127,7 @@ enum BOTAN_FFI_ERROR { BOTAN_FFI_ERROR_TLS_ERROR = -75, BOTAN_FFI_ERROR_HTTP_ERROR = -76, BOTAN_FFI_ERROR_ROUGHTIME_ERROR = -77, + BOTAN_FFI_ERROR_TPM_ERROR = -78, BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100, }; diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h index ed26d2cda0c..32cdee131c3 100644 --- a/src/lib/prov/tpm2/tpm2.h +++ b/src/lib/prov/tpm2/tpm2.h @@ -27,6 +27,11 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Error final : public Exception { TSS2_RC code() const { return m_rc; } + int error_code() const noexcept override { + // RC is uint32 but the maximum value is within int32 range as per tss2_common.h + return static_cast(m_rc); + } + std::string error_message() const; private: diff --git a/src/lib/prov/tpm2/tpm2_rng.cpp b/src/lib/prov/tpm2/tpm2_rng.cpp index 8e12a9f7db2..2a90e1a50ab 100644 --- a/src/lib/prov/tpm2/tpm2_rng.cpp +++ b/src/lib/prov/tpm2/tpm2_rng.cpp @@ -15,13 +15,10 @@ namespace Botan { -namespace { -constexpr size_t MAX_STIR_RANDOM_SIZE = 128; // From specification of tpm2-tool's tpm2_stirrandom -} // anonymous namespace - void TPM2_RNG::fill_bytes_with_input(std::span output, std::span input) { + constexpr size_t MAX_STIR_RANDOM_SIZE = 128; // From specification of tpm2-tool's tpm2_stirrandom + BufferSlicer in(input); - BufferStuffer out(output); while(!in.empty()) { TPM2B_SENSITIVE_DATA data; @@ -31,16 +28,18 @@ void TPM2_RNG::fill_bytes_with_input(std::span output, std::spanget(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); } + BufferStuffer out(output); while(!out.full()) { TPM2B_DIGEST* digest = nullptr; const auto requested_bytes = std::min(sizeof(digest->buffer), out.remaining_capacity()); check_tss2_rc("GetRandom", Esys_GetRandom(m_ctx->get(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, requested_bytes, &digest)); + // Ensure Esys_Free(digest) is called even if assertions fail and we leave this block + auto clean_buffer = scoped_cleanup([&digest] { Esys_Free(digest); }); + BOTAN_ASSERT_NOMSG(digest->size == requested_bytes); out.append({digest->buffer, digest->size}); - - Esys_Free(digest); } } diff --git a/src/python/botan3.py b/src/python/botan3.py index 4d135fe891b..3a1d908b6aa 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -2155,10 +2155,8 @@ def zfec_decode(k, n, indexes, inputs): # 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")) - self.__obj = c_void_p(0) - rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj), tcti) + rc = _DLL.botan_tpm2_ctx_init(byref(self.__obj), _ctype_str(tcti_nameconf)) if rc == -40: # 'Not Implemented' raise BotanException("TPM2 is not implemented in this build configuration", rc) From 2ab6008d0ed9a28935626ec3d307c96e12db754f Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Fri, 14 Jun 2024 11:42:56 +0200 Subject: [PATCH 12/16] Restructure tpm2.h to avoid external includes in public headers --- src/lib/prov/tpm2/info.txt | 4 ++++ src/lib/prov/tpm2/tpm2.cpp | 40 +++++++++++++++++++++++++--------- src/lib/prov/tpm2/tpm2.h | 24 ++++++-------------- src/lib/prov/tpm2/tpm2_rng.cpp | 12 ++++++++-- src/lib/prov/tpm2/tpm2_util.h | 25 +++++++++++++++++++++ 5 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 src/lib/prov/tpm2/tpm2_util.h diff --git a/src/lib/prov/tpm2/info.txt b/src/lib/prov/tpm2/info.txt index a1487d75fb6..63409938ec5 100644 --- a/src/lib/prov/tpm2/info.txt +++ b/src/lib/prov/tpm2/info.txt @@ -17,6 +17,10 @@ all -> tss2-esys,tss2-rc,tss2-tctildr rng + +tpm2_util.h + + tpm2.h tpm2_rng.h diff --git a/src/lib/prov/tpm2/tpm2.cpp b/src/lib/prov/tpm2/tpm2.cpp index f1ce599491a..74ca2efb9a7 100644 --- a/src/lib/prov/tpm2/tpm2.cpp +++ b/src/lib/prov/tpm2/tpm2.cpp @@ -9,19 +9,27 @@ #include #include +#include #include +#include #include namespace Botan { -TPM2_Error::TPM2_Error(std::string_view location, TSS2_RC rc) : +TPM2_Error::TPM2_Error(std::string_view location, uint32_t rc) : Exception(fmt("TPM2 Exception in {}: Code {} ({})", location, rc, Tss2_RC_Decode(rc))), m_rc(rc) {} std::string TPM2_Error::error_message() const { return Tss2_RC_Decode(m_rc); } +class TPM2_Context::Impl { + public: + TSS2_TCTI_CONTEXT* m_tcti_ctx; + ESYS_CONTEXT* m_ctx; +}; + std::shared_ptr TPM2_Context::create(std::optional tcti_nameconf) { const auto tcti_nameconf_ptr = [&]() -> const char* { if(tcti_nameconf.has_value()) { @@ -30,30 +38,42 @@ std::shared_ptr TPM2_Context::create(std::optional tc return nullptr; } }(); + // We cannot std::make_shared as the constructor is private return std::shared_ptr(new TPM2_Context(tcti_nameconf_ptr)); } -TPM2_Context::TPM2_Context(const char* tcti_nameconf) { - check_tss2_rc("TCTI Initialization", Tss2_TctiLdr_Initialize(tcti_nameconf, &m_tcti_ctx)); - check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_ctx, m_tcti_ctx, nullptr /* ABI version */)); +TPM2_Context::TPM2_Context(const char* tcti_nameconf) : m_impl(std::make_unique()) { + check_tss2_rc("TCTI Initialization", Tss2_TctiLdr_Initialize(tcti_nameconf, &m_impl->m_tcti_ctx)); + check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_impl->m_ctx, m_impl->m_tcti_ctx, nullptr /* ABI version */)); } -TPM2_Context::TPM2_Context(TPM2_Context&& ctx) noexcept : m_ctx(ctx.m_ctx) { - ctx.m_ctx = nullptr; +TPM2_Context::TPM2_Context(TPM2_Context&& ctx) noexcept { + m_impl->m_ctx = ctx.m_impl->m_ctx; + m_impl->m_tcti_ctx = ctx.m_impl->m_tcti_ctx; + + ctx.m_impl->m_ctx = nullptr; + ctx.m_impl->m_tcti_ctx = nullptr; } TPM2_Context& TPM2_Context::operator=(TPM2_Context&& ctx) noexcept { if(this != &ctx) { - m_ctx = ctx.m_ctx; - ctx.m_ctx = nullptr; + m_impl->m_ctx = ctx.m_impl->m_ctx; + m_impl->m_tcti_ctx = ctx.m_impl->m_tcti_ctx; + + ctx.m_impl->m_ctx = nullptr; + ctx.m_impl->m_tcti_ctx = nullptr; } return *this; } +void* TPM2_Context::get() { + return m_impl->m_ctx; +} + TPM2_Context::~TPM2_Context() { - Esys_Finalize(&m_ctx); - Tss2_TctiLdr_Finalize(&m_tcti_ctx); + Esys_Finalize(&m_impl->m_ctx); + Tss2_TctiLdr_Finalize(&m_impl->m_tcti_ctx); } } // namespace Botan diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h index 32cdee131c3..fe45c8b3453 100644 --- a/src/lib/prov/tpm2/tpm2.h +++ b/src/lib/prov/tpm2/tpm2.h @@ -11,21 +11,16 @@ #include -#include #include -#include -#include -#include - namespace Botan { class BOTAN_PUBLIC_API(3, 6) TPM2_Error final : public Exception { public: - TPM2_Error(std::string_view location, TSS2_RC rc); + TPM2_Error(std::string_view location, uint32_t rc); ErrorType error_type() const noexcept override { return ErrorType::TPMError; } - TSS2_RC code() const { return m_rc; } + uint32_t code() const { return m_rc; } int error_code() const noexcept override { // RC is uint32 but the maximum value is within int32 range as per tss2_common.h @@ -35,15 +30,9 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Error final : public Exception { std::string error_message() const; private: - TSS2_RC m_rc; + uint32_t m_rc; }; -inline void check_tss2_rc(std::string_view location, TSS2_RC rc) { - if(rc != TSS2_RC_SUCCESS) { - throw TPM2_Error(location, rc); - } -} - class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { public: /** @@ -59,14 +48,15 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { TPM2_Context& operator=(const TPM2_Context&) = delete; TPM2_Context& operator=(TPM2_Context&& ctx) noexcept; - ESYS_CONTEXT* get() { return m_ctx; } + // Return an ESYS_CONTEXT* for use in other TPM2 functions. + void* get(); private: TPM2_Context(const char* tcti_nameconf); private: - TSS2_TCTI_CONTEXT* m_tcti_ctx; - ESYS_CONTEXT* m_ctx; + class Impl; // PImpl to avoid TPM2-TSS includes in this header + std::unique_ptr m_impl; }; } // namespace Botan diff --git a/src/lib/prov/tpm2/tpm2_rng.cpp b/src/lib/prov/tpm2/tpm2_rng.cpp index 2a90e1a50ab..77e42199515 100644 --- a/src/lib/prov/tpm2/tpm2_rng.cpp +++ b/src/lib/prov/tpm2/tpm2_rng.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -25,7 +26,9 @@ void TPM2_RNG::fill_bytes_with_input(std::span output, std::spanget(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); + check_tss2_rc( + "StirRandom", + Esys_StirRandom(static_cast(m_ctx->get()), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); } BufferStuffer out(output); @@ -33,7 +36,12 @@ void TPM2_RNG::fill_bytes_with_input(std::span output, std::spanbuffer), out.remaining_capacity()); check_tss2_rc("GetRandom", - Esys_GetRandom(m_ctx->get(), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, requested_bytes, &digest)); + Esys_GetRandom(static_cast(m_ctx->get()), + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + requested_bytes, + &digest)); // Ensure Esys_Free(digest) is called even if assertions fail and we leave this block auto clean_buffer = scoped_cleanup([&digest] { Esys_Free(digest); }); diff --git a/src/lib/prov/tpm2/tpm2_util.h b/src/lib/prov/tpm2/tpm2_util.h new file mode 100644 index 00000000000..812c83ac1ce --- /dev/null +++ b/src/lib/prov/tpm2/tpm2_util.h @@ -0,0 +1,25 @@ +/* +* TPM 2 internal utilities +* (C) 2024 Jack Lloyd +* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TPM2_UTIL_H_ +#define BOTAN_TPM2_UTIL_H_ + +#include + +#include + +namespace Botan { + +inline void check_tss2_rc(std::string_view location, TSS2_RC rc) { + if(rc != TSS2_RC_SUCCESS) { + throw TPM2_Error(location, rc); + } +} +} // namespace Botan + +#endif From 70be24644aefeaa2d57ccfd105d45b5697a40d21 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Fri, 14 Jun 2024 14:08:39 +0200 Subject: [PATCH 13/16] Address comments regarding tpm2.h restructuring --- src/lib/prov/tpm2/tpm2.cpp | 23 +---------------------- src/lib/prov/tpm2/tpm2.h | 9 +++++---- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/lib/prov/tpm2/tpm2.cpp b/src/lib/prov/tpm2/tpm2.cpp index 74ca2efb9a7..0a2c013089d 100644 --- a/src/lib/prov/tpm2/tpm2.cpp +++ b/src/lib/prov/tpm2/tpm2.cpp @@ -24,8 +24,7 @@ std::string TPM2_Error::error_message() const { return Tss2_RC_Decode(m_rc); } -class TPM2_Context::Impl { - public: +struct TPM2_Context::Impl { TSS2_TCTI_CONTEXT* m_tcti_ctx; ESYS_CONTEXT* m_ctx; }; @@ -47,26 +46,6 @@ TPM2_Context::TPM2_Context(const char* tcti_nameconf) : m_impl(std::make_unique< check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_impl->m_ctx, m_impl->m_tcti_ctx, nullptr /* ABI version */)); } -TPM2_Context::TPM2_Context(TPM2_Context&& ctx) noexcept { - m_impl->m_ctx = ctx.m_impl->m_ctx; - m_impl->m_tcti_ctx = ctx.m_impl->m_tcti_ctx; - - ctx.m_impl->m_ctx = nullptr; - ctx.m_impl->m_tcti_ctx = nullptr; -} - -TPM2_Context& TPM2_Context::operator=(TPM2_Context&& ctx) noexcept { - if(this != &ctx) { - m_impl->m_ctx = ctx.m_impl->m_ctx; - m_impl->m_tcti_ctx = ctx.m_impl->m_tcti_ctx; - - ctx.m_impl->m_ctx = nullptr; - ctx.m_impl->m_tcti_ctx = nullptr; - } - - return *this; -} - void* TPM2_Context::get() { return m_impl->m_ctx; } diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h index fe45c8b3453..fa18c080b74 100644 --- a/src/lib/prov/tpm2/tpm2.h +++ b/src/lib/prov/tpm2/tpm2.h @@ -11,6 +11,7 @@ #include +#include #include namespace Botan { @@ -42,20 +43,20 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { static std::shared_ptr create(std::optional tcti_nameconf = {}); TPM2_Context(const TPM2_Context&) = delete; - TPM2_Context(TPM2_Context&& ctx) noexcept; + TPM2_Context(TPM2_Context&& ctx) noexcept = default; ~TPM2_Context(); TPM2_Context& operator=(const TPM2_Context&) = delete; - TPM2_Context& operator=(TPM2_Context&& ctx) noexcept; + TPM2_Context& operator=(TPM2_Context&& ctx) noexcept = default; - // Return an ESYS_CONTEXT* for use in other TPM2 functions. + /// @return an ESYS_CONTEXT* for use in other TPM2 functions. void* get(); private: TPM2_Context(const char* tcti_nameconf); private: - class Impl; // PImpl to avoid TPM2-TSS includes in this header + struct Impl; // PImpl to avoid TPM2-TSS includes in this header std::unique_ptr m_impl; }; From 6e2af38504a197529f709c9a4c9abcbb7febdb69 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 1 Jul 2024 11:14:28 +0200 Subject: [PATCH 14/16] Review comments: Rename TPM2_Context::get() to TPM2_Context::inner_context_object() and add a helper function to safely cast to ESYS_CONTEXT*. --- src/lib/prov/tpm2/tpm2.cpp | 2 +- src/lib/prov/tpm2/tpm2.h | 2 +- src/lib/prov/tpm2/tpm2_rng.cpp | 11 ++--------- src/lib/prov/tpm2/tpm2_util.h | 9 +++++++++ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/lib/prov/tpm2/tpm2.cpp b/src/lib/prov/tpm2/tpm2.cpp index 0a2c013089d..2452b707214 100644 --- a/src/lib/prov/tpm2/tpm2.cpp +++ b/src/lib/prov/tpm2/tpm2.cpp @@ -46,7 +46,7 @@ TPM2_Context::TPM2_Context(const char* tcti_nameconf) : m_impl(std::make_unique< check_tss2_rc("TPM2 Initialization", Esys_Initialize(&m_impl->m_ctx, m_impl->m_tcti_ctx, nullptr /* ABI version */)); } -void* TPM2_Context::get() { +void* TPM2_Context::inner_context_object() { return m_impl->m_ctx; } diff --git a/src/lib/prov/tpm2/tpm2.h b/src/lib/prov/tpm2/tpm2.h index fa18c080b74..ade30eaccfd 100644 --- a/src/lib/prov/tpm2/tpm2.h +++ b/src/lib/prov/tpm2/tpm2.h @@ -50,7 +50,7 @@ class BOTAN_PUBLIC_API(3, 6) TPM2_Context final { TPM2_Context& operator=(TPM2_Context&& ctx) noexcept = default; /// @return an ESYS_CONTEXT* for use in other TPM2 functions. - void* get(); + void* inner_context_object(); private: TPM2_Context(const char* tcti_nameconf); diff --git a/src/lib/prov/tpm2/tpm2_rng.cpp b/src/lib/prov/tpm2/tpm2_rng.cpp index 77e42199515..0b52789549a 100644 --- a/src/lib/prov/tpm2/tpm2_rng.cpp +++ b/src/lib/prov/tpm2/tpm2_rng.cpp @@ -26,9 +26,7 @@ void TPM2_RNG::fill_bytes_with_input(std::span output, std::span(m_ctx->get()), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); + check_tss2_rc("StirRandom", Esys_StirRandom(inner(m_ctx), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &data)); } BufferStuffer out(output); @@ -36,12 +34,7 @@ void TPM2_RNG::fill_bytes_with_input(std::span output, std::spanbuffer), out.remaining_capacity()); check_tss2_rc("GetRandom", - Esys_GetRandom(static_cast(m_ctx->get()), - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - requested_bytes, - &digest)); + Esys_GetRandom(inner(m_ctx), ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, requested_bytes, &digest)); // Ensure Esys_Free(digest) is called even if assertions fail and we leave this block auto clean_buffer = scoped_cleanup([&digest] { Esys_Free(digest); }); diff --git a/src/lib/prov/tpm2/tpm2_util.h b/src/lib/prov/tpm2/tpm2_util.h index 812c83ac1ce..98cd203011f 100644 --- a/src/lib/prov/tpm2/tpm2_util.h +++ b/src/lib/prov/tpm2/tpm2_util.h @@ -11,6 +11,7 @@ #include +#include #include namespace Botan { @@ -20,6 +21,14 @@ inline void check_tss2_rc(std::string_view location, TSS2_RC rc) { throw TPM2_Error(location, rc); } } + +inline ESYS_CONTEXT* inner(const std::shared_ptr& ctx) { + BOTAN_ASSERT_NOMSG(ctx != nullptr); + auto inner = ctx->inner_context_object(); + BOTAN_ASSERT_NOMSG(inner != nullptr); + return static_cast(inner); +} + } // namespace Botan #endif From 34c7d9ac0cc7c1bc3b786caa5605a2e9542b97da Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 8 Jul 2024 11:01:48 +0200 Subject: [PATCH 15/16] Review comment: Move TPM2 FFI Declarations to end of file --- src/lib/ffi/ffi.h | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index f6ff58ad86e..debfbaac106 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -260,33 +260,6 @@ BOTAN_FFI_EXPORT(2, 3) int botan_base64_decode(const char* base64_str, size_t in */ typedef struct botan_rng_struct* botan_rng_t; -/** -* TPM2 context -*/ -typedef struct botan_tpm2_ctx_struct* botan_tpm2_ctx_t; - -/** -* Initialize a TPM2 context -* @param ctx_out output TPM2 context -* @param tcti_nameconf TCTI config (may be nullpointer) -* @return 0 on success -*/ -BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf); - -/** -* Frees all resouces of a TPM2 context -* @param ctx TPM2 context -* @return 0 on success -*/ -BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx); - -/** -* Initialize a random number generator object via TPM2 -* @param rng_out rng object to create -* @param ctx TPM2 context -*/ -BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx); - /** * Initialize a random number generator object * @param rng rng object @@ -2218,6 +2191,33 @@ BOTAN_FFI_EXPORT(3, 0) int botan_zfec_decode( size_t K, size_t N, const size_t* indexes, uint8_t* const* inputs, size_t shareSize, uint8_t** outputs); +/** +* TPM2 context +*/ +typedef struct botan_tpm2_ctx_struct* botan_tpm2_ctx_t; + +/** +* Initialize a TPM2 context +* @param ctx_out output TPM2 context +* @param tcti_nameconf TCTI config (may be nullpointer) +* @return 0 on success +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf); + +/** +* Frees all resouces of a TPM2 context +* @param ctx TPM2 context +* @return 0 on success +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx); + +/** +* Initialize a random number generator object via TPM2 +* @param rng_out rng object to create +* @param ctx TPM2 context +*/ +BOTAN_FFI_EXPORT(3, 6) int botan_tpm2_rng_init(botan_rng_t* rng_out, botan_tpm2_ctx_t ctx); + #ifdef __cplusplus } #endif From f09eb9f5b92fe5eefea8ab994e8aa07d90495ac1 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 8 Jul 2024 11:02:26 +0200 Subject: [PATCH 16/16] Review comment: Remove Botan_Tests:: --- src/tests/test_tpm2.cpp | 74 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/tests/test_tpm2.cpp b/src/tests/test_tpm2.cpp index 184025d0c28..1c88336b6a1 100644 --- a/src/tests/test_tpm2.cpp +++ b/src/tests/test_tpm2.cpp @@ -38,43 +38,43 @@ std::vector test_tpm2_rng() { auto rng = Botan::TPM2_RNG(ctx); return { - Botan_Tests::CHECK("Basic functionalities", - [&](Test::Result& result) { - result.confirm("Accepts input", rng.accepts_input()); - result.confirm("Is seeded", rng.is_seeded()); - result.test_eq("Right name", rng.name(), "TPM2_RNG"); - - result.test_no_throw("Clear", [&] { rng.clear(); }); - }), - Botan_Tests::CHECK("Random number generation", - [&](Test::Result& result) { - std::array buf1 = {}; - rng.randomize(buf1); - result.confirm("Is at least not 0 (8)", not_zero_64(buf1)); - - std::array buf2 = {}; - rng.randomize(buf2); - result.confirm("Is at least not 0 (15)", not_zero_64(buf2)); - - std::array buf3 = {}; - rng.randomize(buf3); - result.confirm("Is at least not 0 (256)", not_zero_64(buf3)); - }), - - Botan_Tests::CHECK("Randomize with inputs", - [&](Test::Result& result) { - std::array buf1 = {}; - rng.randomize_with_input(buf1, std::array{}); - result.confirm("Randomized with inputs is at least not 0 (9)", not_zero_64(buf1)); - - std::array buf2 = {}; - rng.randomize_with_input(buf2, std::array{}); - result.confirm("Randomized with inputs is at least not 0 (66)", not_zero_64(buf2)); - - std::array buf3 = {}; - rng.randomize_with_input(buf3, std::array{}); - result.confirm("Randomized with inputs is at least not 0 (256)", not_zero_64(buf3)); - }), + CHECK("Basic functionalities", + [&](Test::Result& result) { + result.confirm("Accepts input", rng.accepts_input()); + result.confirm("Is seeded", rng.is_seeded()); + result.test_eq("Right name", rng.name(), "TPM2_RNG"); + + result.test_no_throw("Clear", [&] { rng.clear(); }); + }), + CHECK("Random number generation", + [&](Test::Result& result) { + std::array buf1 = {}; + rng.randomize(buf1); + result.confirm("Is at least not 0 (8)", not_zero_64(buf1)); + + std::array buf2 = {}; + rng.randomize(buf2); + result.confirm("Is at least not 0 (15)", not_zero_64(buf2)); + + std::array buf3 = {}; + rng.randomize(buf3); + result.confirm("Is at least not 0 (256)", not_zero_64(buf3)); + }), + + CHECK("Randomize with inputs", + [&](Test::Result& result) { + std::array buf1 = {}; + rng.randomize_with_input(buf1, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (9)", not_zero_64(buf1)); + + std::array buf2 = {}; + rng.randomize_with_input(buf2, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (66)", not_zero_64(buf2)); + + std::array buf3 = {}; + rng.randomize_with_input(buf3, std::array{}); + result.confirm("Randomized with inputs is at least not 0 (256)", not_zero_64(buf3)); + }), }; } } // namespace