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

randombit / botan / 22835645575

09 Mar 2026 02:17AM UTC coverage: 90.183% (-0.001%) from 90.184%
22835645575

Pull #5423

github

web-flow
Merge 8f65abe96 into cdaa9c0ff
Pull Request #5423: Add z/OS support with clang compiler

103788 of 115086 relevant lines covered (90.18%)

11566961.3 hits per line

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

82.94
/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
#if defined(__MVS__)
22
// z/OS has a bug with thread_local
23
   #define thread_local
24
#endif
25

26
namespace Botan_FFI {
27

28
namespace {
29

30

31
// NOLINTNEXTLINE(*-avoid-non-const-global-variables)
32
thread_local std::string g_last_exception_what;
98,128✔
33

34
int ffi_map_error_type(Botan::ErrorType err) {
15✔
35
   switch(err) {
15✔
36
      case Botan::ErrorType::Unknown:
37
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
38

39
      case Botan::ErrorType::SystemError:
×
40
      case Botan::ErrorType::IoError:
×
41
      case Botan::ErrorType::Pkcs11Error:
×
42
      case Botan::ErrorType::CommonCryptoError:
×
43
      case Botan::ErrorType::ZlibError:
×
44
      case Botan::ErrorType::Bzip2Error:
×
45
      case Botan::ErrorType::LzmaError:
×
46
      case Botan::ErrorType::DatabaseError:
×
47
         return BOTAN_FFI_ERROR_SYSTEM_ERROR;
×
48

49
      case Botan::ErrorType::TPMError:
×
50
         return BOTAN_FFI_ERROR_TPM_ERROR;
×
51

52
      case Botan::ErrorType::NotImplemented:
53
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
54
      case Botan::ErrorType::OutOfMemory:
×
55
         return BOTAN_FFI_ERROR_OUT_OF_MEMORY;
×
56
      case Botan::ErrorType::InternalError:
×
57
         return BOTAN_FFI_ERROR_INTERNAL_ERROR;
×
58
      case Botan::ErrorType::InvalidObjectState:
5✔
59
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
5✔
60
      case Botan::ErrorType::KeyNotSet:
2✔
61
         return BOTAN_FFI_ERROR_KEY_NOT_SET;
2✔
62
      case Botan::ErrorType::InvalidArgument:
5✔
63
      case Botan::ErrorType::InvalidNonceLength:
5✔
64
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
5✔
65

66
      case Botan::ErrorType::EncodingFailure:
1✔
67
      case Botan::ErrorType::DecodingFailure:
1✔
68
         return BOTAN_FFI_ERROR_INVALID_INPUT;
1✔
69

70
      case Botan::ErrorType::InvalidTag:
×
71
         return BOTAN_FFI_ERROR_BAD_MAC;
×
72

73
      case Botan::ErrorType::InvalidKeyLength:
×
74
         return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH;
×
75
      case Botan::ErrorType::LookupError:
76
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
77

78
      case Botan::ErrorType::HttpError:
×
79
         return BOTAN_FFI_ERROR_HTTP_ERROR;
×
80
      case Botan::ErrorType::TLSError:
×
81
         return BOTAN_FFI_ERROR_TLS_ERROR;
×
82
      case Botan::ErrorType::RoughtimeError:
×
83
         return BOTAN_FFI_ERROR_ROUGHTIME_ERROR;
×
84
   }
85

86
   return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
87
}
88

89
}  // namespace
90

91
void ffi_clear_last_exception() {
98,097✔
92
   g_last_exception_what.clear();
98,097✔
93
}
98,088✔
94

95
int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) {
22✔
96
   g_last_exception_what.assign(exn);
22✔
97

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

106
   return rc;
22✔
107
}
22✔
108

109
int ffi_error_exception_thrown(const char* func_name, const char* exn, Botan::ErrorType err) {
15✔
110
   return ffi_error_exception_thrown(func_name, exn, ffi_map_error_type(err));
15✔
111
}
112

113
int botan_view_str_bounce_fn(botan_view_ctx vctx, const char* str, size_t len) {
74✔
114
   return botan_view_bin_bounce_fn(vctx, reinterpret_cast<const uint8_t*>(str), len);
74✔
115
}
116

117
int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t* buf, size_t len) {
168✔
118
   if(vctx == nullptr || buf == nullptr) {
168✔
119
      return BOTAN_FFI_ERROR_NULL_POINTER;
120
   }
121

122
   const botan_view_bounce_struct* ctx = static_cast<botan_view_bounce_struct*>(vctx);
168✔
123

124
   const size_t avail = *ctx->out_len;
168✔
125
   *ctx->out_len = len;
168✔
126

127
   if(avail < len || ctx->out_ptr == nullptr) {
168✔
128
      if(ctx->out_ptr != nullptr) {
78✔
129
         Botan::clear_mem(ctx->out_ptr, avail);
×
130
      }
131
      return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
78✔
132
   } else {
133
      Botan::copy_mem(ctx->out_ptr, buf, len);
90✔
134
      return BOTAN_FFI_SUCCESS;
90✔
135
   }
136
}
137

138
}  // namespace Botan_FFI
139

140
extern "C" {
141

142
using namespace Botan_FFI;
143

144
const char* botan_error_last_exception_message() {
9✔
145
   return g_last_exception_what.c_str();
9✔
146
}
147

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

153
      case BOTAN_FFI_INVALID_VERIFIER:
1✔
154
         return "Invalid verifier";
1✔
155

156
      case BOTAN_FFI_ERROR_INVALID_INPUT:
2✔
157
         return "Invalid input";
2✔
158

159
      case BOTAN_FFI_ERROR_BAD_MAC:
1✔
160
         return "Invalid authentication code";
1✔
161

162
      case BOTAN_FFI_ERROR_NO_VALUE:
2✔
163
         return "No value available";
2✔
164

165
      case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE:
2✔
166
         return "Insufficient buffer space";
2✔
167

168
      case BOTAN_FFI_ERROR_STRING_CONVERSION_ERROR:
1✔
169
         return "String conversion error";
1✔
170

171
      case BOTAN_FFI_ERROR_EXCEPTION_THROWN:
1✔
172
         return "Exception thrown";
1✔
173

174
      case BOTAN_FFI_ERROR_OUT_OF_MEMORY:
1✔
175
         return "Out of memory";
1✔
176

177
      case BOTAN_FFI_ERROR_SYSTEM_ERROR:
1✔
178
         return "Error while calling system API";
1✔
179

180
      case BOTAN_FFI_ERROR_INTERNAL_ERROR:
1✔
181
         return "Internal error";
1✔
182

183
      case BOTAN_FFI_ERROR_BAD_FLAG:
1✔
184
         return "Bad flag";
1✔
185

186
      case BOTAN_FFI_ERROR_NULL_POINTER:
1✔
187
         return "Null pointer argument";
1✔
188

189
      case BOTAN_FFI_ERROR_BAD_PARAMETER:
1✔
190
         return "Bad parameter";
1✔
191

192
      case BOTAN_FFI_ERROR_KEY_NOT_SET:
1✔
193
         return "Key not set on object";
1✔
194

195
      case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH:
1✔
196
         return "Invalid key length";
1✔
197

198
      case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE:
4✔
199
         return "Invalid object state";
4✔
200

201
      case BOTAN_FFI_ERROR_OUT_OF_RANGE:
1✔
202
         return "Index out of range";
1✔
203

204
      case BOTAN_FFI_ERROR_NOT_IMPLEMENTED:
5✔
205
         return "Not implemented";
5✔
206

207
      case BOTAN_FFI_ERROR_INVALID_OBJECT:
1✔
208
         return "Invalid object handle";
1✔
209

210
      case BOTAN_FFI_ERROR_TLS_ERROR:
1✔
211
         return "TLS error";
1✔
212

213
      case BOTAN_FFI_ERROR_HTTP_ERROR:
1✔
214
         return "HTTP error";
1✔
215

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

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

229
int botan_ffi_supports_api(uint32_t api_version) {
7✔
230
   // This is the API introduced in 3.11
231
   if(api_version == 20260303) {
7✔
232
      return BOTAN_FFI_SUCCESS;
233
   }
234

235
   // This is the API introduced in 3.10
236
   if(api_version == 20250829) {
5✔
237
      return BOTAN_FFI_SUCCESS;
238
   }
239

240
   // This is the API introduced in 3.8
241
   if(api_version == 20250506) {
5✔
242
      return BOTAN_FFI_SUCCESS;
243
   }
244

245
   // This is the API introduced in 3.4
246
   if(api_version == 20240408) {
5✔
247
      return BOTAN_FFI_SUCCESS;
248
   }
249

250
   // This is the API introduced in 3.2
251
   if(api_version == 20231009) {
5✔
252
      return BOTAN_FFI_SUCCESS;
253
   }
254

255
   // This is the API introduced in 3.1
256
   if(api_version == 20230711) {
5✔
257
      return BOTAN_FFI_SUCCESS;
258
   }
259

260
   // This is the API introduced in 3.0
261
   if(api_version == 20230403) {
5✔
262
      return BOTAN_FFI_SUCCESS;
263
   }
264

265
   // This is the API introduced in 2.18
266
   if(api_version == 20210220) {
5✔
267
      return BOTAN_FFI_SUCCESS;
268
   }
269

270
   // This is the API introduced in 2.13
271
   if(api_version == 20191214) {
5✔
272
      return BOTAN_FFI_SUCCESS;
273
   }
274

275
   // This is the API introduced in 2.8
276
   if(api_version == 20180713) {
5✔
277
      return BOTAN_FFI_SUCCESS;
278
   }
279

280
   // This is the API introduced in 2.3
281
   if(api_version == 20170815) {
4✔
282
      return BOTAN_FFI_SUCCESS;
283
   }
284

285
   // This is the API introduced in 2.1
286
   if(api_version == 20170327) {
3✔
287
      return BOTAN_FFI_SUCCESS;
288
   }
289

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

295
   // Something else:
296
   return -1;
297
}
298

299
const char* botan_version_string() {
2✔
300
   return Botan::version_cstr();
2✔
301
}
302

303
uint32_t botan_version_major() {
2✔
304
   return Botan::version_major();
2✔
305
}
306

307
uint32_t botan_version_minor() {
2✔
308
   return Botan::version_minor();
2✔
309
}
310

311
uint32_t botan_version_patch() {
1✔
312
   return Botan::version_patch();
1✔
313
}
314

315
uint32_t botan_version_datestamp() {
1✔
316
   return Botan::version_datestamp();
1✔
317
}
318

319
int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) {
28✔
320
   auto same = Botan::CT::is_equal(x, y, len);
28✔
321
   // Return 0 if same or -1 otherwise
322
   return static_cast<int>(same.select(1, 0)) - 1;
28✔
323
}
324

325
int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) {
×
326
   return botan_constant_time_compare(x, y, len);
×
327
}
328

329
int botan_scrub_mem(void* mem, size_t bytes) {
1✔
330
   Botan::secure_scrub_memory(mem, bytes);
1✔
331
   return BOTAN_FFI_SUCCESS;
1✔
332
}
333

334
int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) {
3✔
335
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
336
      const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0;
3✔
337
      Botan::hex_encode(out, in, len, uppercase);
3✔
338
      return BOTAN_FFI_SUCCESS;
339
   });
3✔
340
}
341

342
int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
343
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
344
      const std::vector<uint8_t> bin = Botan::hex_decode(hex_str, in_len);
2✔
345
      return Botan_FFI::write_vec_output(out, out_len, bin);
2✔
346
   });
4✔
347
}
348

349
int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) {
2✔
350
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
351
      const std::string base64 = Botan::base64_encode(in, len);
2✔
352
      return Botan_FFI::write_str_output(out, out_len, base64);
2✔
353
   });
4✔
354
}
355

356
int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
357
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
358
      if(*out_len < Botan::base64_decode_max_output(in_len)) {
2✔
359
         *out_len = Botan::base64_decode_max_output(in_len);
1✔
360
         return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
1✔
361
      }
362

363
      *out_len = Botan::base64_decode(out, std::string(base64_str, in_len));
1✔
364
      return BOTAN_FFI_SUCCESS;
1✔
365
   });
2✔
366
}
367
}
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