Botan 3.4.0
Crypto and TLS for C&
ffi.cpp
Go to the documentation of this file.
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
19namespace Botan_FFI {
20
21// NOLINTNEXTLINE(*-avoid-non-const-global-variables)
22thread_local std::string g_last_exception_what;
23
24int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) {
25 g_last_exception_what.assign(exn);
26
27 std::string val;
28 if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") == true && !val.empty()) {
29 static_cast<void>(std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc));
30 }
31 return rc;
32}
33
34int botan_view_str_bounce_fn(botan_view_ctx vctx, const char* str, size_t len) {
35 return botan_view_bin_bounce_fn(vctx, reinterpret_cast<const uint8_t*>(str), len);
36}
37
38int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t* buf, size_t len) {
39 if(vctx == nullptr || buf == nullptr) {
41 }
42
43 botan_view_bounce_struct* ctx = static_cast<botan_view_bounce_struct*>(vctx);
44
45 const size_t avail = *ctx->out_len;
46 *ctx->out_len = len;
47
48 if(avail < len || ctx->out_ptr == nullptr) {
49 if(ctx->out_ptr) {
50 Botan::clear_mem(ctx->out_ptr, avail);
51 }
53 } else {
54 Botan::copy_mem(ctx->out_ptr, buf, len);
55 return BOTAN_FFI_SUCCESS;
56 }
57}
58
59namespace {
60
61int ffi_map_error_type(Botan::ErrorType err) {
62 switch(err) {
65
76
90
94
97
102
109 }
110
112}
113
114} // namespace
115
116int ffi_guard_thunk(const char* func_name, const std::function<int()>& thunk) {
117 g_last_exception_what.clear();
118
119 try {
120 return thunk();
121 } catch(std::bad_alloc&) {
122 return ffi_error_exception_thrown(func_name, "bad_alloc", BOTAN_FFI_ERROR_OUT_OF_MEMORY);
123 } catch(Botan_FFI::FFI_Error& e) {
124 return ffi_error_exception_thrown(func_name, e.what(), e.error_code());
125 } catch(Botan::Exception& e) {
126 return ffi_error_exception_thrown(func_name, e.what(), ffi_map_error_type(e.error_type()));
127 } catch(std::exception& e) {
128 return ffi_error_exception_thrown(func_name, e.what());
129 } catch(...) {
130 return ffi_error_exception_thrown(func_name, "unknown exception");
131 }
132
134}
135
136} // namespace Botan_FFI
137
138extern "C" {
139
140using namespace Botan_FFI;
141
143 return g_last_exception_what.c_str();
144}
145
146const char* botan_error_description(int err) {
147 switch(err) {
149 return "OK";
150
152 return "Invalid verifier";
153
155 return "Invalid input";
156
158 return "Invalid authentication code";
159
161 return "Insufficient buffer space";
162
164 return "String conversion error";
165
167 return "Exception thrown";
168
170 return "Out of memory";
171
173 return "Error while calling system API";
174
176 return "Internal error";
177
179 return "Bad flag";
180
182 return "Null pointer argument";
183
185 return "Bad parameter";
186
188 return "Key not set on object";
189
191 return "Invalid key length";
192
194 return "Invalid object state";
195
197 return "Not implemented";
198
200 return "Invalid object handle";
201
203 return "TLS error";
204
206 return "HTTP error";
207
209 return "Unknown error";
210
211 default:
212 return "Unknown error";
213 }
214}
215
216/*
217* Versioning
218*/
220 return BOTAN_HAS_FFI;
221}
222
223int botan_ffi_supports_api(uint32_t api_version) {
224 // This is the API introduced in 3.4
225 if(api_version == 20240408) {
226 return BOTAN_FFI_SUCCESS;
227 }
228
229 // This is the API introduced in 3.2
230 if(api_version == 20231009) {
231 return BOTAN_FFI_SUCCESS;
232 }
233
234 // This is the API introduced in 3.1
235 if(api_version == 20230711) {
236 return BOTAN_FFI_SUCCESS;
237 }
238
239 // This is the API introduced in 3.0
240 if(api_version == 20230403) {
241 return BOTAN_FFI_SUCCESS;
242 }
243
244 // This is the API introduced in 2.18
245 if(api_version == 20210220) {
246 return BOTAN_FFI_SUCCESS;
247 }
248
249 // This is the API introduced in 2.13
250 if(api_version == 20191214) {
251 return BOTAN_FFI_SUCCESS;
252 }
253
254 // This is the API introduced in 2.8
255 if(api_version == 20180713) {
256 return BOTAN_FFI_SUCCESS;
257 }
258
259 // This is the API introduced in 2.3
260 if(api_version == 20170815) {
261 return BOTAN_FFI_SUCCESS;
262 }
263
264 // This is the API introduced in 2.1
265 if(api_version == 20170327) {
266 return BOTAN_FFI_SUCCESS;
267 }
268
269 // This is the API introduced in 2.0
270 if(api_version == 20150515) {
271 return BOTAN_FFI_SUCCESS;
272 }
273
274 // Something else:
275 return -1;
276}
277
278const char* botan_version_string() {
279 return Botan::version_cstr();
280}
281
283 return Botan::version_major();
284}
285
287 return Botan::version_minor();
288}
289
291 return Botan::version_patch();
292}
293
296}
297
298int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) {
299 auto same = Botan::CT::is_equal(x, y, len);
300 // Return 0 if same or -1 otherwise
301 return static_cast<int>(same.select(1, 0)) - 1;
302}
303
304int 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
308int botan_scrub_mem(void* mem, size_t bytes) {
309 Botan::secure_scrub_memory(mem, bytes);
310 return BOTAN_FFI_SUCCESS;
311}
312
313int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) {
314 return ffi_guard_thunk(__func__, [=]() -> int {
315 const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0;
316 Botan::hex_encode(out, in, len, uppercase);
317 return BOTAN_FFI_SUCCESS;
318 });
319}
320
321int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) {
322 return ffi_guard_thunk(__func__, [=]() -> int {
323 const std::vector<uint8_t> bin = Botan::hex_decode(hex_str, in_len);
324 return Botan_FFI::write_vec_output(out, out_len, bin);
325 });
326}
327
328int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) {
329 return ffi_guard_thunk(__func__, [=]() -> int {
330 const std::string base64 = Botan::base64_encode(in, len);
331 return Botan_FFI::write_str_output(out, out_len, base64);
332 });
333}
334
335int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) {
336 return ffi_guard_thunk(__func__, [=]() -> int {
337 if(*out_len < Botan::base64_decode_max_output(in_len)) {
338 *out_len = Botan::base64_decode_max_output(in_len);
340 }
341
342 *out_len = Botan::base64_decode(out, std::string(base64_str, in_len));
343 return BOTAN_FFI_SUCCESS;
344 });
345}
346}
const char * what() const noexcept override
Definition exceptn.h:93
Botan::ErrorType error_type() const noexcept override
Definition ffi_util.h:26
int error_code() const noexcept override
Definition ffi_util.h:24
uint32_t botan_version_datestamp()
Definition ffi.cpp:294
int botan_same_mem(const uint8_t *x, const uint8_t *y, size_t len)
Definition ffi.cpp:304
const char * botan_version_string()
Definition ffi.cpp:278
int botan_base64_decode(const char *base64_str, size_t in_len, uint8_t *out, size_t *out_len)
Definition ffi.cpp:335
uint32_t botan_version_patch()
Definition ffi.cpp:290
int botan_base64_encode(const uint8_t *in, size_t len, char *out, size_t *out_len)
Definition ffi.cpp:328
int botan_scrub_mem(void *mem, size_t bytes)
Definition ffi.cpp:308
int botan_hex_encode(const uint8_t *in, size_t len, char *out, uint32_t flags)
Definition ffi.cpp:313
uint32_t botan_version_major()
Definition ffi.cpp:282
uint32_t botan_ffi_api_version()
Definition ffi.cpp:219
int botan_ffi_supports_api(uint32_t api_version)
Definition ffi.cpp:223
const char * botan_error_description(int err)
Definition ffi.cpp:146
uint32_t botan_version_minor()
Definition ffi.cpp:286
int botan_constant_time_compare(const uint8_t *x, const uint8_t *y, size_t len)
Definition ffi.cpp:298
int botan_hex_decode(const char *hex_str, size_t in_len, uint8_t *out, size_t *out_len)
Definition ffi.cpp:321
const char * botan_error_last_exception_message()
Definition ffi.cpp:142
#define BOTAN_FFI_HEX_LOWER_CASE
Definition ffi.h:225
void * botan_view_ctx
Definition ffi.h:134
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition ffi.h:124
@ BOTAN_FFI_ERROR_INVALID_KEY_LENGTH
Definition ffi.h:121
@ BOTAN_FFI_ERROR_KEY_NOT_SET
Definition ffi.h:120
@ BOTAN_FFI_ERROR_TLS_ERROR
Definition ffi.h:127
@ BOTAN_FFI_ERROR_EXCEPTION_THROWN
Definition ffi.h:112
@ BOTAN_FFI_ERROR_OUT_OF_MEMORY
Definition ffi.h:113
@ BOTAN_FFI_ERROR_INTERNAL_ERROR
Definition ffi.h:115
@ BOTAN_FFI_INVALID_VERIFIER
Definition ffi.h:104
@ BOTAN_FFI_ERROR_INVALID_OBJECT
Definition ffi.h:125
@ BOTAN_FFI_ERROR_UNKNOWN_ERROR
Definition ffi.h:131
@ BOTAN_FFI_ERROR_HTTP_ERROR
Definition ffi.h:128
@ BOTAN_FFI_ERROR_BAD_FLAG
Definition ffi.h:117
@ BOTAN_FFI_ERROR_INVALID_INPUT
Definition ffi.h:106
@ BOTAN_FFI_ERROR_STRING_CONVERSION_ERROR
Definition ffi.h:110
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:118
@ BOTAN_FFI_SUCCESS
Definition ffi.h:103
@ BOTAN_FFI_ERROR_SYSTEM_ERROR
Definition ffi.h:114
@ BOTAN_FFI_ERROR_ROUGHTIME_ERROR
Definition ffi.h:129
@ BOTAN_FFI_ERROR_INVALID_OBJECT_STATE
Definition ffi.h:122
@ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE
Definition ffi.h:109
@ BOTAN_FFI_ERROR_BAD_MAC
Definition ffi.h:107
@ BOTAN_FFI_ERROR_BAD_PARAMETER
Definition ffi.h:119
#define BOTAN_HAS_FFI
Definition build.h:220
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:345
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition os_utils.cpp:409
int ffi_error_exception_thrown(const char *func_name, const char *exn, int rc)
Definition ffi.cpp:24
int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t *buf, size_t len)
Definition ffi.cpp:38
int botan_view_str_bounce_fn(botan_view_ctx vctx, const char *str, size_t len)
Definition ffi.cpp:34
int write_str_output(uint8_t out[], size_t *out_len, std::string_view str)
Definition ffi_util.h:205
thread_local std::string g_last_exception_what
Definition ffi.cpp:22
int ffi_guard_thunk(const char *func_name, const std::function< int()> &thunk)
Definition ffi.cpp:116
int write_vec_output(uint8_t out[], size_t *out_len, const std::vector< uint8_t, Alloc > &buf)
Definition ffi_util.h:201
uint32_t version_minor()
Definition version.cpp:86
uint32_t version_major()
Definition version.cpp:82
const char * version_cstr()
Definition version.cpp:33
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition base64.cpp:146
uint32_t version_datestamp()
Definition version.cpp:75
void secure_scrub_memory(void *ptr, size_t n)
Definition os_utils.cpp:87
uint32_t version_patch()
Definition version.cpp:90
size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition base64.cpp:154
ErrorType
Definition exceptn.h:20
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
Definition hex.cpp:33
size_t base64_decode_max_output(size_t input_length)
Definition base64.cpp:186
size_t hex_decode(uint8_t output[], const char input[], size_t input_length, size_t &input_consumed, bool ignore_ws)
Definition hex.cpp:81
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:120