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

randombit / botan / 11294885908

11 Oct 2024 03:15PM UTC coverage: 90.981% (-0.01%) from 90.994%
11294885908

push

github

web-flow
Merge pull request #4361 from Rohde-Schwarz/feature/tpm2_rng_in_python

TPM2: Basic bindings in FFI & Python

89998 of 98920 relevant lines covered (90.98%)

8979753.1 hits per line

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

80.12
/src/lib/ffi/ffi.cpp
1
/*
2
* (C) 2015,2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/ffi.h>
8

9
#include <botan/base64.h>
10
#include <botan/hex.h>
11
#include <botan/mem_ops.h>
12
#include <botan/version.h>
13
#include <botan/internal/ct_utils.h>
14
#include <botan/internal/ffi_util.h>
15
#include <botan/internal/os_utils.h>
16
#include <cstdio>
17
#include <cstdlib>
18

19
namespace Botan_FFI {
20

21
// NOLINTNEXTLINE(*-avoid-non-const-global-variables)
22
thread_local std::string g_last_exception_what;
94,907✔
23

24
int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) {
13✔
25
   g_last_exception_what.assign(exn);
13✔
26

27
   std::string val;
13✔
28
   if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") == true && !val.empty()) {
13✔
29
      static_cast<void>(std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc));
×
30
   }
31
   return rc;
13✔
32
}
13✔
33

34
int botan_view_str_bounce_fn(botan_view_ctx vctx, const char* str, size_t len) {
68✔
35
   return botan_view_bin_bounce_fn(vctx, reinterpret_cast<const uint8_t*>(str), len);
68✔
36
}
37

38
int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t* buf, size_t len) {
155✔
39
   if(vctx == nullptr || buf == nullptr) {
155✔
40
      return BOTAN_FFI_ERROR_NULL_POINTER;
41
   }
42

43
   botan_view_bounce_struct* ctx = static_cast<botan_view_bounce_struct*>(vctx);
155✔
44

45
   const size_t avail = *ctx->out_len;
155✔
46
   *ctx->out_len = len;
155✔
47

48
   if(avail < len || ctx->out_ptr == nullptr) {
155✔
49
      if(ctx->out_ptr) {
72✔
50
         Botan::clear_mem(ctx->out_ptr, avail);
×
51
      }
52
      return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
72✔
53
   } else {
54
      Botan::copy_mem(ctx->out_ptr, buf, len);
83✔
55
      return BOTAN_FFI_SUCCESS;
83✔
56
   }
57
}
58

59
namespace {
60

61
int ffi_map_error_type(Botan::ErrorType err) {
7✔
62
   switch(err) {
7✔
63
      case Botan::ErrorType::Unknown:
64
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
65

66
      case Botan::ErrorType::SystemError:
×
67
      case Botan::ErrorType::IoError:
×
68
      case Botan::ErrorType::Pkcs11Error:
×
69
      case Botan::ErrorType::CommonCryptoError:
×
70
      case Botan::ErrorType::ZlibError:
×
71
      case Botan::ErrorType::Bzip2Error:
×
72
      case Botan::ErrorType::LzmaError:
×
73
      case Botan::ErrorType::DatabaseError:
×
74
         return BOTAN_FFI_ERROR_SYSTEM_ERROR;
×
75

76
      case Botan::ErrorType::TPMError:
×
77
         return BOTAN_FFI_ERROR_TPM_ERROR;
×
78

79
      case Botan::ErrorType::NotImplemented:
80
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
81
      case Botan::ErrorType::OutOfMemory:
×
82
         return BOTAN_FFI_ERROR_OUT_OF_MEMORY;
×
83
      case Botan::ErrorType::InternalError:
×
84
         return BOTAN_FFI_ERROR_INTERNAL_ERROR;
×
85
      case Botan::ErrorType::InvalidObjectState:
2✔
86
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
2✔
87
      case Botan::ErrorType::KeyNotSet:
2✔
88
         return BOTAN_FFI_ERROR_KEY_NOT_SET;
2✔
89
      case Botan::ErrorType::InvalidArgument:
2✔
90
      case Botan::ErrorType::InvalidNonceLength:
2✔
91
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
2✔
92

93
      case Botan::ErrorType::EncodingFailure:
1✔
94
      case Botan::ErrorType::DecodingFailure:
1✔
95
         return BOTAN_FFI_ERROR_INVALID_INPUT;
1✔
96

97
      case Botan::ErrorType::InvalidTag:
×
98
         return BOTAN_FFI_ERROR_BAD_MAC;
×
99

100
      case Botan::ErrorType::InvalidKeyLength:
×
101
         return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH;
×
102
      case Botan::ErrorType::LookupError:
103
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
104

105
      case Botan::ErrorType::HttpError:
×
106
         return BOTAN_FFI_ERROR_HTTP_ERROR;
×
107
      case Botan::ErrorType::TLSError:
×
108
         return BOTAN_FFI_ERROR_TLS_ERROR;
×
109
      case Botan::ErrorType::RoughtimeError:
×
110
         return BOTAN_FFI_ERROR_ROUGHTIME_ERROR;
×
111
   }
112

113
   return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
114
}
115

116
}  // namespace
117

118
int ffi_guard_thunk(const char* func_name, const std::function<int()>& thunk) {
94,892✔
119
   g_last_exception_what.clear();
94,892✔
120

121
   try {
94,892✔
122
      return thunk();
189,784✔
123
   } catch(std::bad_alloc&) {
13✔
124
      return ffi_error_exception_thrown(func_name, "bad_alloc", BOTAN_FFI_ERROR_OUT_OF_MEMORY);
×
125
   } catch(Botan_FFI::FFI_Error& e) {
6✔
126
      return ffi_error_exception_thrown(func_name, e.what(), e.error_code());
6✔
127
   } catch(Botan::Exception& e) {
13✔
128
      return ffi_error_exception_thrown(func_name, e.what(), ffi_map_error_type(e.error_type()));
7✔
129
   } catch(std::exception& e) {
7✔
130
      return ffi_error_exception_thrown(func_name, e.what());
×
131
   } catch(...) {
×
132
      return ffi_error_exception_thrown(func_name, "unknown exception");
×
133
   }
×
134
}
135

136
}  // namespace Botan_FFI
137

138
extern "C" {
139

140
using namespace Botan_FFI;
141

142
const char* botan_error_last_exception_message() {
2✔
143
   return g_last_exception_what.c_str();
2✔
144
}
145

146
const char* botan_error_description(int err) {
152✔
147
   switch(err) {
152✔
148
      case BOTAN_FFI_SUCCESS:
149
         return "OK";
150

151
      case BOTAN_FFI_INVALID_VERIFIER:
1✔
152
         return "Invalid verifier";
1✔
153

154
      case BOTAN_FFI_ERROR_INVALID_INPUT:
2✔
155
         return "Invalid input";
2✔
156

157
      case BOTAN_FFI_ERROR_BAD_MAC:
1✔
158
         return "Invalid authentication code";
1✔
159

160
      case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE:
1✔
161
         return "Insufficient buffer space";
1✔
162

163
      case BOTAN_FFI_ERROR_STRING_CONVERSION_ERROR:
1✔
164
         return "String conversion error";
1✔
165

166
      case BOTAN_FFI_ERROR_EXCEPTION_THROWN:
1✔
167
         return "Exception thrown";
1✔
168

169
      case BOTAN_FFI_ERROR_OUT_OF_MEMORY:
1✔
170
         return "Out of memory";
1✔
171

172
      case BOTAN_FFI_ERROR_SYSTEM_ERROR:
1✔
173
         return "Error while calling system API";
1✔
174

175
      case BOTAN_FFI_ERROR_INTERNAL_ERROR:
1✔
176
         return "Internal error";
1✔
177

178
      case BOTAN_FFI_ERROR_BAD_FLAG:
1✔
179
         return "Bad flag";
1✔
180

181
      case BOTAN_FFI_ERROR_NULL_POINTER:
1✔
182
         return "Null pointer argument";
1✔
183

184
      case BOTAN_FFI_ERROR_BAD_PARAMETER:
1✔
185
         return "Bad parameter";
1✔
186

187
      case BOTAN_FFI_ERROR_KEY_NOT_SET:
1✔
188
         return "Key not set on object";
1✔
189

190
      case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH:
1✔
191
         return "Invalid key length";
1✔
192

193
      case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE:
1✔
194
         return "Invalid object state";
1✔
195

196
      case BOTAN_FFI_ERROR_NOT_IMPLEMENTED:
2✔
197
         return "Not implemented";
2✔
198

199
      case BOTAN_FFI_ERROR_INVALID_OBJECT:
1✔
200
         return "Invalid object handle";
1✔
201

202
      case BOTAN_FFI_ERROR_TLS_ERROR:
1✔
203
         return "TLS error";
1✔
204

205
      case BOTAN_FFI_ERROR_HTTP_ERROR:
1✔
206
         return "HTTP error";
1✔
207

208
      case BOTAN_FFI_ERROR_UNKNOWN_ERROR:
209
         return "Unknown error";
210

211
      default:
212
         return "Unknown error";
213
   }
214
}
215

216
/*
217
* Versioning
218
*/
219
uint32_t botan_ffi_api_version() {
4✔
220
   return BOTAN_HAS_FFI;
4✔
221
}
222

223
int botan_ffi_supports_api(uint32_t api_version) {
7✔
224
   // This is the API introduced in 3.4
225
   if(api_version == 20240408) {
7✔
226
      return BOTAN_FFI_SUCCESS;
227
   }
228

229
   // This is the API introduced in 3.2
230
   if(api_version == 20231009) {
5✔
231
      return BOTAN_FFI_SUCCESS;
232
   }
233

234
   // This is the API introduced in 3.1
235
   if(api_version == 20230711) {
5✔
236
      return BOTAN_FFI_SUCCESS;
237
   }
238

239
   // This is the API introduced in 3.0
240
   if(api_version == 20230403) {
5✔
241
      return BOTAN_FFI_SUCCESS;
242
   }
243

244
   // This is the API introduced in 2.18
245
   if(api_version == 20210220) {
5✔
246
      return BOTAN_FFI_SUCCESS;
247
   }
248

249
   // This is the API introduced in 2.13
250
   if(api_version == 20191214) {
5✔
251
      return BOTAN_FFI_SUCCESS;
252
   }
253

254
   // This is the API introduced in 2.8
255
   if(api_version == 20180713) {
5✔
256
      return BOTAN_FFI_SUCCESS;
257
   }
258

259
   // This is the API introduced in 2.3
260
   if(api_version == 20170815) {
4✔
261
      return BOTAN_FFI_SUCCESS;
262
   }
263

264
   // This is the API introduced in 2.1
265
   if(api_version == 20170327) {
3✔
266
      return BOTAN_FFI_SUCCESS;
267
   }
268

269
   // This is the API introduced in 2.0
270
   if(api_version == 20150515) {
2✔
271
      return BOTAN_FFI_SUCCESS;
1✔
272
   }
273

274
   // Something else:
275
   return -1;
276
}
277

278
const char* botan_version_string() {
2✔
279
   return Botan::version_cstr();
2✔
280
}
281

282
uint32_t botan_version_major() {
2✔
283
   return Botan::version_major();
2✔
284
}
285

286
uint32_t botan_version_minor() {
2✔
287
   return Botan::version_minor();
2✔
288
}
289

290
uint32_t botan_version_patch() {
1✔
291
   return Botan::version_patch();
1✔
292
}
293

294
uint32_t botan_version_datestamp() {
1✔
295
   return Botan::version_datestamp();
1✔
296
}
297

298
int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) {
28✔
299
   auto same = Botan::CT::is_equal(x, y, len);
28✔
300
   // Return 0 if same or -1 otherwise
301
   return static_cast<int>(same.select(1, 0)) - 1;
28✔
302
}
303

304
int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) {
×
305
   return botan_constant_time_compare(x, y, len);
×
306
}
307

308
int botan_scrub_mem(void* mem, size_t bytes) {
1✔
309
   Botan::secure_scrub_memory(mem, bytes);
1✔
310
   return BOTAN_FFI_SUCCESS;
1✔
311
}
312

313
int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) {
3✔
314
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
315
      const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0;
3✔
316
      Botan::hex_encode(out, in, len, uppercase);
3✔
317
      return BOTAN_FFI_SUCCESS;
3✔
318
   });
3✔
319
}
320

321
int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
322
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
323
      const std::vector<uint8_t> bin = Botan::hex_decode(hex_str, in_len);
2✔
324
      return Botan_FFI::write_vec_output(out, out_len, bin);
2✔
325
   });
4✔
326
}
327

328
int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) {
2✔
329
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
330
      const std::string base64 = Botan::base64_encode(in, len);
2✔
331
      return Botan_FFI::write_str_output(out, out_len, base64);
2✔
332
   });
4✔
333
}
334

335
int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
336
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
337
      if(*out_len < Botan::base64_decode_max_output(in_len)) {
2✔
338
         *out_len = Botan::base64_decode_max_output(in_len);
1✔
339
         return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
1✔
340
      }
341

342
      *out_len = Botan::base64_decode(out, std::string(base64_str, in_len));
1✔
343
      return BOTAN_FFI_SUCCESS;
1✔
344
   });
2✔
345
}
346
}
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

© 2025 Coveralls, Inc