Botan 3.4.0
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 <botan/exceptn.h>
11#include <botan/ffi.h>
12#include <botan/mem_ops.h>
13#include <cstdint>
14#include <functional>
15#include <memory>
16#include <stdexcept>
17
18namespace Botan_FFI {
19
21 public:
22 FFI_Error(std::string_view what, int err_code) : Exception("FFI error", what), m_err_code(err_code) {}
23
24 int error_code() const noexcept override { return m_err_code; }
25
27
28 private:
29 int m_err_code;
30};
31
32template <typename T, uint32_t MAGIC>
34 public:
35 botan_struct(std::unique_ptr<T> obj) : m_magic(MAGIC), m_obj(std::move(obj)) {}
36
37 virtual ~botan_struct() {
38 m_magic = 0;
39 m_obj.reset();
40 }
41
42 bool magic_ok() const { return (m_magic == MAGIC); }
43
44 T* unsafe_get() const { return m_obj.get(); }
45
46 private:
47 uint32_t m_magic = 0;
48 std::unique_ptr<T> m_obj;
49};
50
51#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \
52 struct NAME final : public Botan_FFI::botan_struct<TYPE, MAGIC> { \
53 explicit NAME(std::unique_ptr<TYPE> x) : botan_struct(std::move(x)) {} \
54 }
55
56#define BOTAN_FFI_DECLARE_DUMMY_STRUCT(NAME, MAGIC) \
57 struct NAME final : public Botan_FFI::botan_struct<int, MAGIC> {}
58
59// Declared in ffi.cpp
60int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc = BOTAN_FFI_ERROR_EXCEPTION_THROWN);
61
62template <typename T, uint32_t M>
64 if(!p) {
65 throw FFI_Error("Null pointer argument", BOTAN_FFI_ERROR_NULL_POINTER);
66 }
67 if(p->magic_ok() == false) {
68 throw FFI_Error("Bad magic in ffi object", BOTAN_FFI_ERROR_INVALID_OBJECT);
69 }
70
71 if(T* t = p->unsafe_get()) {
72 return *t;
73 }
74
75 throw FFI_Error("Invalid object pointer", BOTAN_FFI_ERROR_INVALID_OBJECT);
76}
77
78int ffi_guard_thunk(const char* func_name, const std::function<int()>& thunk);
79
80template <typename T, uint32_t M, typename F>
81int botan_ffi_visit(botan_struct<T, M>* o, F func, const char* func_name) {
82 using RetT = std::invoke_result_t<F, T&>;
83 static_assert(std::is_void_v<RetT> || std::is_same_v<RetT, BOTAN_FFI_ERROR> || std::is_same_v<RetT, int>,
84 "BOTAN_FFI_DO must be used with a block that returns either nothing, int or BOTAN_FFI_ERROR");
85
86 if(!o) {
88 }
89
90 if(o->magic_ok() == false) {
92 }
93
94 T* p = o->unsafe_get();
95 if(p == nullptr) {
97 }
98
99 if constexpr(std::is_void_v<RetT>) {
100 return ffi_guard_thunk(func_name, [&] {
101 func(*p);
102 return BOTAN_FFI_SUCCESS;
103 });
104 } else {
105 return ffi_guard_thunk(func_name, [&] { return func(*p); });
106 }
107}
108
109// TODO: C++20 introduces std::source_location which will allow to eliminate this
110// macro altogether. Instead, using code would just call the C++ function
111// that makes use of std::source_location like so:
112//
113// template<typename T, uint32_t M, typename F>
114// int botan_ffi_visit(botan_struct<T, M>* obj, F func,
115// const std::source_location sl = std::source_location::current())
116// {
117// // [...]
118// if constexpr(...)
119// {
120// return ffi_guard_thunk(sl.function_name(), [&] { return func(*p); })
121// }
122// // [...]
123// }
124#define BOTAN_FFI_VISIT(obj, lambda) botan_ffi_visit(obj, lambda, __func__)
125
126template <typename T, uint32_t M>
127int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name) {
128 return ffi_guard_thunk(func_name, [=]() -> int {
129 // ignore delete of null objects
130 if(obj == nullptr) {
131 return BOTAN_FFI_SUCCESS;
132 }
133
134 if(obj->magic_ok() == false) {
135 return BOTAN_FFI_ERROR_INVALID_OBJECT;
136 }
137
138 delete obj;
139 return BOTAN_FFI_SUCCESS;
140 });
141}
142
143#define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__)
144
145template <typename Alloc>
146inline int invoke_view_callback(botan_view_bin_fn view, botan_view_ctx ctx, const std::vector<uint8_t, Alloc>& buf) {
147 return view(ctx, buf.data(), buf.size());
148}
149
150inline int invoke_view_callback(botan_view_str_fn view, botan_view_ctx ctx, std::string_view str) {
151 return view(ctx, str.data(), str.size() + 1);
152}
153
155 uint8_t* out_ptr;
156 size_t* out_len;
157};
158
159int botan_view_bin_bounce_fn(botan_view_ctx ctx, const uint8_t* buf, size_t len);
160int botan_view_str_bounce_fn(botan_view_ctx ctx, const char* str, size_t len);
161
162template <typename Fn, typename... Args>
163int copy_view_bin(uint8_t out[], size_t* out_len, Fn fn, Args... args) {
165 ctx.out_ptr = out;
166 ctx.out_len = out_len;
167 return fn(args..., &ctx, botan_view_bin_bounce_fn);
168}
169
170template <typename Fn, typename... Args>
171int copy_view_str(uint8_t out[], size_t* out_len, Fn fn, Args... args) {
172 if(fn == nullptr) {
174 }
176 ctx.out_ptr = out;
177 ctx.out_len = out_len;
178 return fn(args..., &ctx, botan_view_str_bounce_fn);
179}
180
181inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len) {
182 if(out_len == nullptr) {
184 }
185
186 const size_t avail = *out_len;
187 *out_len = buf_len;
188
189 if((avail >= buf_len) && (out != nullptr)) {
190 Botan::copy_mem(out, buf, buf_len);
191 return BOTAN_FFI_SUCCESS;
192 } else {
193 if(out != nullptr) {
194 Botan::clear_mem(out, avail);
195 }
197 }
198}
199
200template <typename Alloc>
201int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf) {
202 return write_output(out, out_len, buf.data(), buf.size());
203}
204
205inline int write_str_output(uint8_t out[], size_t* out_len, std::string_view str) {
206 return write_output(out, out_len, Botan::cast_char_ptr_to_uint8(str.data()), str.size() + 1);
207}
208
209inline int write_str_output(char out[], size_t* out_len, std::string_view str) {
210 return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str);
211}
212
213inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec) {
214 return write_output(Botan::cast_char_ptr_to_uint8(out), out_len, str_vec.data(), str_vec.size());
215}
216
217} // namespace Botan_FFI
218
219#endif
Botan::ErrorType error_type() const noexcept override
Definition ffi_util.h:26
FFI_Error(std::string_view what, int err_code)
Definition ffi_util.h:22
int error_code() const noexcept override
Definition ffi_util.h:24
int(* final)(unsigned char *, CTX *)
#define BOTAN_UNSTABLE_API
Definition compiler.h:44
int(* botan_view_bin_fn)(botan_view_ctx view_ctx, const uint8_t *data, size_t len)
Definition ffi.h:143
void * botan_view_ctx
Definition ffi.h:134
@ BOTAN_FFI_ERROR_EXCEPTION_THROWN
Definition ffi.h:112
@ BOTAN_FFI_ERROR_INVALID_OBJECT
Definition ffi.h:125
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:118
@ BOTAN_FFI_SUCCESS
Definition ffi.h:103
@ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE
Definition ffi.h:109
int(* botan_view_str_fn)(botan_view_ctx view_ctx, const char *str, size_t len)
Definition ffi.h:152
FE_25519 T
Definition ge.cpp:34
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 botan_ffi_visit(botan_struct< T, M > *o, F func, const char *func_name)
Definition ffi_util.h:81
int copy_view_bin(uint8_t out[], size_t *out_len, Fn fn, Args... args)
Definition ffi_util.h:163
int write_str_output(uint8_t out[], size_t *out_len, std::string_view str)
Definition ffi_util.h:205
int ffi_delete_object(botan_struct< T, M > *obj, const char *func_name)
Definition ffi_util.h:127
T & safe_get(botan_struct< T, M > *p)
Definition ffi_util.h:63
int invoke_view_callback(botan_view_bin_fn view, botan_view_ctx ctx, const std::vector< uint8_t, Alloc > &buf)
Definition ffi_util.h:146
int copy_view_str(uint8_t out[], size_t *out_len, Fn fn, Args... args)
Definition ffi_util.h:171
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
int write_output(uint8_t out[], size_t *out_len, const uint8_t buf[], size_t buf_len)
Definition ffi_util.h:181
ErrorType
Definition exceptn.h:20
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
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition mem_ops.h:275
T * unsafe_get() const
Definition ffi_util.h:44
virtual ~botan_struct()
Definition ffi_util.h:37
botan_struct(std::unique_ptr< T > obj)
Definition ffi_util.h:35
bool magic_ok() const
Definition ffi_util.h:42