• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 11779157375

11 Nov 2024 01:06PM UTC coverage: 91.065% (-0.008%) from 91.073%
11779157375

push

github

web-flow
Merge pull request #4430 from Rohde-Schwarz/feature/tpm2_external_ctx

Feature: Support external ESYS_CONTEXT in TPM2

90557 of 99442 relevant lines covered (91.07%)

9347784.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.71
/src/lib/ffi/ffi_tpm2.cpp
1
/*
2
* (C) 2024 Jack Lloyd
3
* (C) 2024 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity GmbH
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/ffi.h>
9

10
#include <botan/internal/ffi_pkey.h>
11
#include <botan/internal/ffi_rng.h>
12
#include <botan/internal/ffi_util.h>
13

14
#if defined(BOTAN_HAS_TPM2)
15
   #include <botan/tpm2_context.h>
16
   #include <botan/tpm2_key.h>
17
   #include <botan/tpm2_rng.h>
18
   #include <botan/tpm2_session.h>
19

20
   #if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
21
      #include <botan/tpm2_crypto_backend.h>
22
   #endif
23
#endif
24

25
extern "C" {
26

27
using namespace Botan_FFI;
28

29
#if defined(BOTAN_HAS_TPM2)
30

31
// These wrappers are required since BOTAN_FFI_DECLARE_STRUCT internally
32
// produces a unique pointer, but the TPM types are meant to be used as
33
// shared pointers.
34

35
struct botan_tpm2_ctx_wrapper {
7✔
36
      std::shared_ptr<Botan::TPM2::Context> ctx;
37
};
38

39
struct botan_tpm2_session_wrapper {
7✔
40
      std::shared_ptr<Botan::TPM2::Session> session;
41
};
42

43
BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_ctx_struct, botan_tpm2_ctx_wrapper, 0xD2B95E15);
3✔
44
BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_session_struct, botan_tpm2_session_wrapper, 0x9ACCAB52);
3✔
45

46
   #if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
47
BOTAN_FFI_DECLARE_STRUCT(botan_tpm2_crypto_backend_state_struct, Botan::TPM2::CryptoCallbackState, 0x1AC84DE5);
1✔
48
   #endif
49

50
}  // extern "C"
51

52
namespace {
53

54
Botan::TPM2::SessionBundle sessions(botan_tpm2_session_t s1, botan_tpm2_session_t s2, botan_tpm2_session_t s3) {
6✔
55
   return Botan::TPM2::SessionBundle((s1 != nullptr) ? safe_get(s1).session : nullptr,
6✔
56
                                     (s2 != nullptr) ? safe_get(s2).session : nullptr,
12✔
57
                                     (s3 != nullptr) ? safe_get(s3).session : nullptr);
12✔
58
}
59

60
}  // namespace
61

62
extern "C" {
63

64
#endif
65

66
int botan_tpm2_supports_crypto_backend() {
3✔
67
#if defined(BOTAN_HAS_TPM2)
68
   return Botan::TPM2::Context::supports_botan_crypto_backend() ? 1 : 0;
3✔
69
#else
70
   return 0;
71
#endif
72
}
73

74
int botan_tpm2_ctx_init(botan_tpm2_ctx_t* ctx_out, const char* tcti_nameconf) {
×
75
#if defined(BOTAN_HAS_TPM2)
76
   return ffi_guard_thunk(__func__, [=]() -> int {
×
77
      if(ctx_out == nullptr) {
×
78
         return BOTAN_FFI_ERROR_NULL_POINTER;
79
      }
80
      auto ctx = std::make_unique<botan_tpm2_ctx_wrapper>();
×
81

82
      auto tcti = [=]() -> std::optional<std::string> {
×
83
         if(tcti_nameconf == nullptr) {
×
84
            return {};
×
85
         } else {
86
            return std::string(tcti_nameconf);
×
87
         }
88
      }();
×
89

90
      ctx->ctx = Botan::TPM2::Context::create(std::move(tcti));
×
91
      *ctx_out = new botan_tpm2_ctx_struct(std::move(ctx));
×
92
      return BOTAN_FFI_SUCCESS;
×
93
   });
×
94
#else
95
   BOTAN_UNUSED(ctx_out, tcti_nameconf);
96
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
97
#endif
98
}
99

100
int botan_tpm2_ctx_init_ex(botan_tpm2_ctx_t* ctx_out, const char* tcti_name, const char* tcti_conf) {
2✔
101
#if defined(BOTAN_HAS_TPM2)
102
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
103
      if(ctx_out == nullptr) {
2✔
104
         return BOTAN_FFI_ERROR_NULL_POINTER;
105
      }
106
      auto ctx = std::make_unique<botan_tpm2_ctx_wrapper>();
2✔
107

108
      auto tcti_name_str = [=]() -> std::optional<std::string> {
×
109
         if(tcti_name == nullptr) {
2✔
110
            return {};
×
111
         } else {
112
            return std::string(tcti_name);
4✔
113
         }
114
      }();
2✔
115

116
      auto tcti_conf_str = [=]() -> std::optional<std::string> {
×
117
         if(tcti_conf == nullptr) {
2✔
118
            return {};
×
119
         } else {
120
            return std::string(tcti_conf);
4✔
121
         }
122
      }();
2✔
123

124
      ctx->ctx = Botan::TPM2::Context::create(std::move(tcti_name_str), std::move(tcti_conf_str));
8✔
125
      *ctx_out = new botan_tpm2_ctx_struct(std::move(ctx));
2✔
126
      return BOTAN_FFI_SUCCESS;
2✔
127
   });
6✔
128
#else
129
   BOTAN_UNUSED(ctx_out, tcti_name, tcti_conf);
130
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
131
#endif
132
}
133

134
int botan_tpm2_ctx_from_esys(botan_tpm2_ctx_t* ctx_out, ESYS_CONTEXT* esys_ctx) {
1✔
135
#if defined(BOTAN_HAS_TPM2)
136
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
137
      if(ctx_out == nullptr || esys_ctx == nullptr) {
1✔
138
         return BOTAN_FFI_ERROR_NULL_POINTER;
139
      }
140

141
      auto ctx = std::make_unique<botan_tpm2_ctx_wrapper>();
1✔
142
      ctx->ctx = Botan::TPM2::Context::create(esys_ctx);
1✔
143
      *ctx_out = new botan_tpm2_ctx_struct(std::move(ctx));
1✔
144
      return BOTAN_FFI_SUCCESS;
1✔
145
   });
2✔
146
#else
147
   BOTAN_UNUSED(ctx_out, esys_ctx);
148
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
149
#endif
150
}
151

152
int botan_tpm2_ctx_enable_crypto_backend(botan_tpm2_ctx_t ctx, botan_rng_t rng) {
2✔
153
#if defined(BOTAN_HAS_TPM2)
154
   return BOTAN_FFI_VISIT(ctx, [=](botan_tpm2_ctx_wrapper& ctx_wrapper) -> int {
6✔
155
      Botan::RandomNumberGenerator& rng_ref = safe_get(rng);
156

157
      // The lifetime of the RNG used for the crypto backend should be managed
158
      // by the TPM2::Context. Here, we just need to trust the user that they
159
      // keep the passed-in RNG instance intact for the lifetime of the context.
160
      std::shared_ptr<Botan::RandomNumberGenerator> rng_ptr(&rng_ref, [](auto*) {});
161
      ctx_wrapper.ctx->use_botan_crypto_backend(rng_ptr);
162
      return BOTAN_FFI_SUCCESS;
163
   });
164
#else
165
   BOTAN_UNUSED(ctx, rng);
166
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
167
#endif
168
}
169

170
/**
171
 * Frees all resouces of a TPM2 context
172
 * @param ctx TPM2 context
173
 * @return 0 on success
174
 */
175
int botan_tpm2_ctx_destroy(botan_tpm2_ctx_t ctx) {
2✔
176
#if defined(BOTAN_HAS_TPM2)
177
   return BOTAN_FFI_CHECKED_DELETE(ctx);
2✔
178
#else
179
   BOTAN_UNUSED(ctx);
180
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
181
#endif
182
}
183

184
int botan_tpm2_enable_crypto_backend(botan_tpm2_crypto_backend_state_t* cbs_out,
1✔
185
                                     ESYS_CONTEXT* esys_ctx,
186
                                     botan_rng_t rng) {
187
#if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
188
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
189
      if(cbs_out == nullptr || esys_ctx == nullptr) {
1✔
190
         return BOTAN_FFI_ERROR_NULL_POINTER;
191
      }
192

193
      Botan::RandomNumberGenerator& rng_ref = safe_get(rng);
1✔
194

195
      // Here, we just need to trust the user that they keep the passed-in RNG
196
      // instance intact for the lifetime of the context.
197
      std::shared_ptr<Botan::RandomNumberGenerator> rng_ptr(&rng_ref, [](auto*) {});
1✔
198
      *cbs_out = new botan_tpm2_crypto_backend_state_struct(Botan::TPM2::use_botan_crypto_backend(esys_ctx, rng_ptr));
1✔
199
      return BOTAN_FFI_SUCCESS;
1✔
200
   });
2✔
201
#else
202
   BOTAN_UNUSED(cbs_out, esys_ctx, rng);
203
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
204
#endif
205
}
206

207
int botan_tpm2_crypto_backend_state_destroy(botan_tpm2_crypto_backend_state_t cbs) {
1✔
208
#if defined(BOTAN_HAS_TPM2_CRYPTO_BACKEND)
209
   return BOTAN_FFI_CHECKED_DELETE(cbs);
1✔
210
#else
211
   BOTAN_UNUSED(cbs);
212
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
213
#endif
214
}
215

216
int botan_tpm2_rng_init(botan_rng_t* rng_out,
6✔
217
                        botan_tpm2_ctx_t ctx,
218
                        botan_tpm2_session_t s1,
219
                        botan_tpm2_session_t s2,
220
                        botan_tpm2_session_t s3) {
221
#if defined(BOTAN_HAS_TPM2)
222
   return BOTAN_FFI_VISIT(ctx, [=](botan_tpm2_ctx_wrapper& ctx_wrapper) -> int {
18✔
223
      if(rng_out == nullptr) {
224
         return BOTAN_FFI_ERROR_NULL_POINTER;
225
      }
226

227
      *rng_out = new botan_rng_struct(
228
         std::make_unique<Botan::TPM2::RandomNumberGenerator>(ctx_wrapper.ctx, sessions(s1, s2, s3)));
229
      return BOTAN_FFI_SUCCESS;
230
   });
231
#else
232
   BOTAN_UNUSED(rng_out, ctx, s1, s2, s3);
233
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
234
#endif
235
}
236

237
int botan_tpm2_unauthenticated_session_init(botan_tpm2_session_t* session_out, botan_tpm2_ctx_t ctx) {
3✔
238
#if defined(BOTAN_HAS_TPM2)
239
   return BOTAN_FFI_VISIT(ctx, [=](botan_tpm2_ctx_wrapper& ctx_wrapper) -> int {
6✔
240
      if(session_out == nullptr) {
241
         return BOTAN_FFI_ERROR_NULL_POINTER;
242
      }
243

244
      auto session = std::make_unique<botan_tpm2_session_wrapper>();
245
      session->session = Botan::TPM2::Session::unauthenticated_session(ctx_wrapper.ctx);
246
      *session_out = new botan_tpm2_session_struct(std::move(session));
247
      return BOTAN_FFI_SUCCESS;
248
   });
249
#else
250
   BOTAN_UNUSED(session_out, ctx);
251
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
252
#endif
253
}
254

255
int botan_tpm2_session_destroy(botan_tpm2_session_t session) {
2✔
256
#if defined(BOTAN_HAS_TPM2)
257
   return BOTAN_FFI_CHECKED_DELETE(session);
2✔
258
#else
259
   BOTAN_UNUSED(session);
260
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
261
#endif
262
}
263
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc