Botan 2.19.2
Crypto and TLS for C&
ffi_util.h
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#ifndef BOTAN_FFI_UTILS_H_
8#define BOTAN_FFI_UTILS_H_
9
10#include <cstdint>
11#include <memory>
12#include <stdexcept>
13#include <functional>
14#include <botan/exceptn.h>
15#include <botan/mem_ops.h>
16
17namespace Botan_FFI {
18
20 {
21 public:
22 FFI_Error(const std::string& what, int err_code) :
23 Exception("FFI error", what),
24 m_err_code(err_code)
25 {}
26
27 int error_code() const noexcept override { return m_err_code; }
28
30
31 private:
32 int m_err_code;
33 };
34
35template<typename T, uint32_t MAGIC>
37 {
38 public:
39 botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {}
40 virtual ~botan_struct() { m_magic = 0; m_obj.reset(); }
41
42 bool magic_ok() const { return (m_magic == MAGIC); }
43
44 T* unsafe_get() const
45 {
46 return m_obj.get();
47 }
48 private:
49 uint32_t m_magic = 0;
50 std::unique_ptr<T> m_obj;
51 };
52
53#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \
54 struct NAME final : public Botan_FFI::botan_struct<TYPE, MAGIC> { explicit NAME(TYPE* x) : botan_struct(x) {} }
55
56// Declared in ffi.cpp
57int ffi_error_exception_thrown(const char* func_name, const char* exn,
59
60template<typename T, uint32_t M>
62 {
63 if(!p)
64 throw FFI_Error("Null pointer argument", BOTAN_FFI_ERROR_NULL_POINTER);
65 if(p->magic_ok() == false)
66 throw FFI_Error("Bad magic in ffi object", BOTAN_FFI_ERROR_INVALID_OBJECT);
67
68 if(T* t = p->unsafe_get())
69 return *t;
70
71 throw FFI_Error("Invalid object pointer", BOTAN_FFI_ERROR_INVALID_OBJECT);
72 }
73
74int ffi_guard_thunk(const char* func_name, std::function<int ()>);
75
76template<typename T, uint32_t M, typename F>
77int apply_fn(botan_struct<T, M>* o, const char* func_name, F func)
78 {
79 if(!o)
81
82 if(o->magic_ok() == false)
84
85 T* p = o->unsafe_get();
86 if(p == nullptr)
88
89 return ffi_guard_thunk(func_name, [&]() { return func(*p); });
90 }
91
92#define BOTAN_FFI_DO(T, obj, param, block) \
93 apply_fn(obj, __func__, \
94 [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; })
95
96/*
97* Like BOTAN_FFI_DO but with no trailing return with the expectation
98* that the block always returns a value. This exists because otherwise
99* MSVC warns about the dead return after the block in FFI_DO.
100*/
101#define BOTAN_FFI_RETURNING(T, obj, param, block) \
102 apply_fn(obj, __func__, \
103 [=](T& param) -> int { do { block } while(0); })
104
105template<typename T, uint32_t M>
106int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name)
107 {
108 try
109 {
110 if(obj == nullptr)
111 return BOTAN_FFI_SUCCESS; // ignore delete of null objects
112
113 if(obj->magic_ok() == false)
115
116 delete obj;
117 return BOTAN_FFI_SUCCESS;
118 }
119 catch(std::exception& e)
120 {
121 return ffi_error_exception_thrown(func_name, e.what());
122 }
123 catch(...)
124 {
125 return ffi_error_exception_thrown(func_name, "unknown exception");
126 }
127 }
128
129#define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__)
130
131inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len)
132 {
133 if(out_len == nullptr)
135
136 const size_t avail = *out_len;
137 *out_len = buf_len;
138
139 if((avail >= buf_len) && (out != nullptr))
140 {
141 Botan::copy_mem(out, buf, buf_len);
142 return BOTAN_FFI_SUCCESS;
143 }
144 else
145 {
146 if(out != nullptr)
147 {
148 Botan::clear_mem(out, avail);
149 }
151 }
152 }
153
154template<typename Alloc>
155int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
156 {
157 return write_output(out, out_len, buf.data(), buf.size());
158 }
159
160inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str)
161 {
162 return write_output(out, out_len,
164 str.size() + 1);
165 }
166
167inline int write_str_output(char out[], size_t* out_len, const std::string& str)
168 {
169 return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str);
170 }
171
172inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec)
173 {
175 out_len,
176 str_vec.data(),
177 str_vec.size());
178 }
179
180}
181
182#endif
FFI_Error(const std::string &what, int err_code)
Definition: ffi_util.h:22
Botan::ErrorType error_type() const noexcept override
Definition: ffi_util.h:29
int error_code() const noexcept override
Definition: ffi_util.h:27
int(* final)(unsigned char *, CTX *)
#define BOTAN_UNSTABLE_API
Definition: compiler.h:44
@ BOTAN_FFI_ERROR_EXCEPTION_THROWN
Definition: ffi.h:71
@ BOTAN_FFI_ERROR_INVALID_OBJECT
Definition: ffi.h:84
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition: ffi.h:77
@ BOTAN_FFI_SUCCESS
Definition: ffi.h:63
@ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE
Definition: ffi.h:69
fe T
Definition: ge.cpp:37
int apply_fn(botan_struct< T, M > *o, const char *func_name, F func)
Definition: ffi_util.h:77
int ffi_error_exception_thrown(const char *func_name, const char *exn, int rc)
Definition: ffi.cpp:19
int ffi_delete_object(botan_struct< T, M > *obj, const char *func_name)
Definition: ffi_util.h:106
int ffi_guard_thunk(const char *func_name, std::function< int()> thunk)
Definition: ffi.cpp:89
T & safe_get(botan_struct< T, M > *p)
Definition: ffi_util.h:61
int write_str_output(uint8_t out[], size_t *out_len, const std::string &str)
Definition: ffi_util.h:160
int write_vec_output(uint8_t out[], size_t *out_len, const std::vector< uint8_t, Alloc > &buf)
Definition: ffi_util.h:155
int write_output(uint8_t out[], size_t *out_len, const uint8_t buf[], size_t buf_len)
Definition: ffi_util.h:131
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
ErrorType
Definition: exceptn.h:20
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:190
T * unsafe_get() const
Definition: ffi_util.h:44
virtual ~botan_struct()
Definition: ffi_util.h:40
bool magic_ok() const
Definition: ffi_util.h:42