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