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

randombit / botan / 26995937053

04 Jun 2026 09:38PM UTC coverage: 89.394% (-2.3%) from 91.672%
26995937053

push

github

web-flow
Merge pull request #5642 from randombit/jack/prefetch-in-ks

Improve prefetching for table based implementations

110588 of 123708 relevant lines covered (89.39%)

11056434.37 hits per line

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

83.71
/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 <cstdio>
16

17
#if defined(BOTAN_HAS_OS_UTILS)
18
   #include <botan/internal/os_utils.h>
19
#endif
20

21
namespace Botan_FFI {
22

23
namespace {
24

25
// NOLINTNEXTLINE(*-avoid-non-const-global-variables)
26
thread_local std::string g_last_exception_what;
98,293✔
27

28
int ffi_map_error_type(Botan::ErrorType err) {
15✔
29
   switch(err) {
15✔
30
      case Botan::ErrorType::Unknown:
31
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
32

33
      case Botan::ErrorType::SystemError:
×
34
      case Botan::ErrorType::IoError:
×
35
      case Botan::ErrorType::Pkcs11Error:
×
36
      case Botan::ErrorType::CommonCryptoError:
×
37
      case Botan::ErrorType::ZlibError:
×
38
      case Botan::ErrorType::Bzip2Error:
×
39
      case Botan::ErrorType::LzmaError:
×
40
      case Botan::ErrorType::DatabaseError:
×
41
         return BOTAN_FFI_ERROR_SYSTEM_ERROR;
×
42

43
      case Botan::ErrorType::TPMError:
×
44
         return BOTAN_FFI_ERROR_TPM_ERROR;
×
45

46
      case Botan::ErrorType::NotImplemented:
47
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
48
      case Botan::ErrorType::OutOfMemory:
×
49
         return BOTAN_FFI_ERROR_OUT_OF_MEMORY;
×
50
      case Botan::ErrorType::InternalError:
×
51
         return BOTAN_FFI_ERROR_INTERNAL_ERROR;
×
52
      case Botan::ErrorType::InvalidObjectState:
6✔
53
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
6✔
54
      case Botan::ErrorType::KeyNotSet:
2✔
55
         return BOTAN_FFI_ERROR_KEY_NOT_SET;
2✔
56
      case Botan::ErrorType::InvalidArgument:
3✔
57
      case Botan::ErrorType::InvalidNonceLength:
3✔
58
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
3✔
59

60
      case Botan::ErrorType::EncodingFailure:
2✔
61
      case Botan::ErrorType::DecodingFailure:
2✔
62
         return BOTAN_FFI_ERROR_INVALID_INPUT;
2✔
63

64
      case Botan::ErrorType::InvalidTag:
×
65
         return BOTAN_FFI_ERROR_BAD_MAC;
×
66

67
      case Botan::ErrorType::InvalidKeyLength:
×
68
         return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH;
×
69
      case Botan::ErrorType::LookupError:
70
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
71

72
      case Botan::ErrorType::HttpError:
×
73
         return BOTAN_FFI_ERROR_HTTP_ERROR;
×
74
      case Botan::ErrorType::TLSError:
×
75
         return BOTAN_FFI_ERROR_TLS_ERROR;
×
76
      case Botan::ErrorType::RoughtimeError:
×
77
         return BOTAN_FFI_ERROR_ROUGHTIME_ERROR;
×
78
   }
79

80
   return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
81
}
82

83
}  // namespace
84

85
void ffi_clear_last_exception() {
98,262✔
86
   g_last_exception_what.clear();
98,262✔
87
}
98,253✔
88

89
int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) {
22✔
90
   g_last_exception_what.assign(exn);
22✔
91

92
#if defined(BOTAN_HAS_OS_UTILS)
93
   std::string val;
22✔
94
   if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") && !val.empty()) {
22✔
95
      // NOLINTNEXTLINE(*-vararg)
96
      static_cast<void>(std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc));
×
97
   }
98
#endif
99

100
   return rc;
22✔
101
}
22✔
102

103
int ffi_error_exception_thrown(const char* func_name, const char* exn, Botan::ErrorType err) {
15✔
104
   return ffi_error_exception_thrown(func_name, exn, ffi_map_error_type(err));
15✔
105
}
106

107
int botan_view_str_bounce_fn(botan_view_ctx vctx, const char* str, size_t len) {
74✔
108
   return botan_view_bin_bounce_fn(vctx, reinterpret_cast<const uint8_t*>(str), len);
74✔
109
}
110

111
int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t* buf, size_t len) {
168✔
112
   if(any_null_pointers(vctx, buf)) {
168✔
113
      return BOTAN_FFI_ERROR_NULL_POINTER;
114
   }
115

116
   const botan_view_bounce_struct* ctx = static_cast<botan_view_bounce_struct*>(vctx);
168✔
117

118
   if(ctx->out_len == nullptr) {
168✔
119
      return BOTAN_FFI_ERROR_NULL_POINTER;
120
   }
121

122
   const size_t avail = *ctx->out_len;
168✔
123
   *ctx->out_len = len;
168✔
124

125
   if(avail < len || ctx->out_ptr == nullptr) {
168✔
126
      if(ctx->out_ptr != nullptr) {
78✔
127
         Botan::clear_mem(ctx->out_ptr, avail);
×
128
      }
129
      return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
78✔
130
   } else {
131
      Botan::copy_mem(ctx->out_ptr, buf, len);
90✔
132
      return BOTAN_FFI_SUCCESS;
90✔
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() {
9✔
143
   return g_last_exception_what.c_str();
9✔
144
}
145

146
const char* botan_error_description(int err) {
159✔
147
   switch(err) {
159✔
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_NO_VALUE:
2✔
161
         return "No value available";
2✔
162

163
      case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE:
2✔
164
         return "Insufficient buffer space";
2✔
165

166
      case BOTAN_FFI_ERROR_STRING_CONVERSION_ERROR:
1✔
167
         return "String conversion error";
1✔
168

169
      case BOTAN_FFI_ERROR_EXCEPTION_THROWN:
1✔
170
         return "Exception thrown";
1✔
171

172
      case BOTAN_FFI_ERROR_OUT_OF_MEMORY:
1✔
173
         return "Out of memory";
1✔
174

175
      case BOTAN_FFI_ERROR_SYSTEM_ERROR:
1✔
176
         return "Error while calling system API";
1✔
177

178
      case BOTAN_FFI_ERROR_INTERNAL_ERROR:
1✔
179
         return "Internal error";
1✔
180

181
      case BOTAN_FFI_ERROR_BAD_FLAG:
1✔
182
         return "Bad flag";
1✔
183

184
      case BOTAN_FFI_ERROR_NULL_POINTER:
1✔
185
         return "Null pointer argument";
1✔
186

187
      case BOTAN_FFI_ERROR_BAD_PARAMETER:
1✔
188
         return "Bad parameter";
1✔
189

190
      case BOTAN_FFI_ERROR_KEY_NOT_SET:
1✔
191
         return "Key not set on object";
1✔
192

193
      case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH:
1✔
194
         return "Invalid key length";
1✔
195

196
      case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE:
3✔
197
         return "Invalid object state";
3✔
198

199
      case BOTAN_FFI_ERROR_OUT_OF_RANGE:
1✔
200
         return "Index out of range";
1✔
201

202
      case BOTAN_FFI_ERROR_NOT_IMPLEMENTED:
5✔
203
         return "Not implemented";
5✔
204

205
      case BOTAN_FFI_ERROR_INVALID_OBJECT:
1✔
206
         return "Invalid object handle";
1✔
207

208
      case BOTAN_FFI_ERROR_TLS_ERROR:
1✔
209
         return "TLS error";
1✔
210

211
      case BOTAN_FFI_ERROR_HTTP_ERROR:
1✔
212
         return "HTTP error";
1✔
213

214
      case BOTAN_FFI_ERROR_UNKNOWN_ERROR:
128✔
215
      default:
128✔
216
         return "Unknown error";
128✔
217
   }
218
}
219

220
/*
221
* Versioning
222
*/
223
uint32_t botan_ffi_api_version() {
4✔
224
   return BOTAN_HAS_FFI;
4✔
225
}
226

227
int botan_ffi_supports_api(uint32_t api_version) {
7✔
228
   // This is the API introduced in 3.12
229
   if(api_version == 20260506) {
7✔
230
      return BOTAN_FFI_SUCCESS;
231
   }
232

233
   // This is the API introduced in 3.11
234
   if(api_version == 20260303) {
5✔
235
      return BOTAN_FFI_SUCCESS;
236
   }
237

238
   // This is the API introduced in 3.10
239
   if(api_version == 20250829) {
5✔
240
      return BOTAN_FFI_SUCCESS;
241
   }
242

243
   // This is the API introduced in 3.8
244
   if(api_version == 20250506) {
5✔
245
      return BOTAN_FFI_SUCCESS;
246
   }
247

248
   // This is the API introduced in 3.4
249
   if(api_version == 20240408) {
5✔
250
      return BOTAN_FFI_SUCCESS;
251
   }
252

253
   // This is the API introduced in 3.2
254
   if(api_version == 20231009) {
5✔
255
      return BOTAN_FFI_SUCCESS;
256
   }
257

258
   // This is the API introduced in 3.1
259
   if(api_version == 20230711) {
5✔
260
      return BOTAN_FFI_SUCCESS;
261
   }
262

263
   // This is the API introduced in 3.0
264
   if(api_version == 20230403) {
5✔
265
      return BOTAN_FFI_SUCCESS;
266
   }
267

268
   // This is the API introduced in 2.18
269
   if(api_version == 20210220) {
5✔
270
      return BOTAN_FFI_SUCCESS;
271
   }
272

273
   // This is the API introduced in 2.13
274
   if(api_version == 20191214) {
5✔
275
      return BOTAN_FFI_SUCCESS;
276
   }
277

278
   // This is the API introduced in 2.8
279
   if(api_version == 20180713) {
5✔
280
      return BOTAN_FFI_SUCCESS;
281
   }
282

283
   // This is the API introduced in 2.3
284
   if(api_version == 20170815) {
4✔
285
      return BOTAN_FFI_SUCCESS;
286
   }
287

288
   // This is the API introduced in 2.1
289
   if(api_version == 20170327) {
3✔
290
      return BOTAN_FFI_SUCCESS;
291
   }
292

293
   // This is the API introduced in 2.0
294
   if(api_version == 20150515) {
2✔
295
      return BOTAN_FFI_SUCCESS;
1✔
296
   }
297

298
   // Something else:
299
   return -1;
300
}
301

302
const char* botan_version_string() {
2✔
303
   return Botan::version_cstr();
2✔
304
}
305

306
uint32_t botan_version_major() {
2✔
307
   return Botan::version_major();
2✔
308
}
309

310
uint32_t botan_version_minor() {
2✔
311
   return Botan::version_minor();
2✔
312
}
313

314
uint32_t botan_version_patch() {
1✔
315
   return Botan::version_patch();
1✔
316
}
317

318
uint32_t botan_version_datestamp() {
1✔
319
   return Botan::version_datestamp();
1✔
320
}
321

322
int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) {
28✔
323
   if(len > 0 && any_null_pointers(x, y)) {
28✔
324
      return BOTAN_FFI_ERROR_NULL_POINTER;
325
   }
326
   auto same = Botan::CT::is_equal(x, y, len);
28✔
327
   // Return 0 if same or -1 otherwise
328
   return static_cast<int>(same.select(1, 0)) - 1;
28✔
329
}
330

331
int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) {
×
332
   return botan_constant_time_compare(x, y, len);
×
333
}
334

335
int botan_scrub_mem(void* mem, size_t bytes) {
1✔
336
   if(bytes > 0 && mem == nullptr) {
1✔
337
      return BOTAN_FFI_ERROR_NULL_POINTER;
338
   }
339
   Botan::secure_scrub_memory(mem, bytes);
1✔
340
   return BOTAN_FFI_SUCCESS;
1✔
341
}
342

343
int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) {
3✔
344
   if(len > 0 && (in == nullptr || out == nullptr)) {
3✔
345
      return BOTAN_FFI_ERROR_NULL_POINTER;
346
   }
347
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
348
      const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0;
3✔
349
      Botan::hex_encode(out, in, len, uppercase);
3✔
350
      return BOTAN_FFI_SUCCESS;
351
   });
3✔
352
}
353

354
int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
355
   if(any_null_pointers(hex_str, out_len)) {
2✔
356
      return BOTAN_FFI_ERROR_NULL_POINTER;
357
   }
358
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
359
      const std::vector<uint8_t> bin = Botan::hex_decode(hex_str, in_len);
2✔
360
      return Botan_FFI::write_vec_output(out, out_len, bin);
2✔
361
   });
2✔
362
}
363

364
int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) {
2✔
365
   if(len > 0 && in == nullptr) {
2✔
366
      return BOTAN_FFI_ERROR_NULL_POINTER;
367
   }
368
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
369
      const std::string base64 = Botan::base64_encode(in, len);
2✔
370
      return Botan_FFI::write_str_output(out, out_len, base64);
2✔
371
   });
2✔
372
}
373

374
int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
375
   if(any_null_pointers(out, out_len, base64_str)) {
2✔
376
      return BOTAN_FFI_ERROR_NULL_POINTER;
377
   }
378

379
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
380
      if(*out_len < Botan::base64_decode_max_output(in_len)) {
2✔
381
         *out_len = Botan::base64_decode_max_output(in_len);
1✔
382
         return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
1✔
383
      }
384

385
      *out_len = Botan::base64_decode(out, std::string(base64_str, in_len));
1✔
386
      return BOTAN_FFI_SUCCESS;
1✔
387
   });
2✔
388
}
389
}
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