26 RCSID(
"$Id: 6267e530bb6b6102c5630b30becfbf269014360c $")
30 #define LOG_PREFIX "tls"
32 #include <freeradius-devel/tls/base.h>
33 #include <freeradius-devel/tls/engine.h>
34 #include <freeradius-devel/tls/log.h>
35 #include <freeradius-devel/tls/strerror.h>
36 #include <freeradius-devel/util/dlist.h>
37 #include <freeradius-devel/util/rb.h>
38 #include <freeradius-devel/util/strerror.h>
39 #include <freeradius-devel/util/value.h>
41 #if OPENSSL_VERSION_NUMBER < 0x30000000L
42 #include <openssl/engine.h>
54 fr_tls_engine_ctrl_list_t *pre_ctrls;
55 fr_tls_engine_ctrl_list_t *post_ctrls;
72 static int8_t tls_engine_cmp(
void const *one,
void const *two)
78 ret =
CMP(strcmp(a->id, b->id), 0);
79 if (ret != 0)
return ret;
84 if (!a->instance && !b->instance)
return 0;
85 if (!a->instance)
return -1;
86 if (!b->instance)
return +1;
88 return CMP(strcmp(a->instance, b->instance), 0);
98 static void CC_HINT(
nonnull) tls_engine_control_notfound_strerror(ENGINE *e,
char const *bad_ctrl)
110 pool = talloc_pool(NULL, 256);
113 fr_strerror_printf(
"engine %s does not export control %s", ENGINE_get_id(e), bad_ctrl);
115 for (cmd = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, 0, NULL, NULL);
117 cmd = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, cmd, NULL, NULL)) {
118 size_t name_len, desc_len;
122 if (!ENGINE_cmd_is_executable(e, cmd))
continue;
127 name_len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, 0, NULL, NULL);
128 if (
unlikely(name_len == 0))
continue;
130 name = talloc_array(pool,
char, name_len + 1);
133 if (
unlikely(ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, 0,
name, NULL) <= 0))
break;
138 desc_len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, 0, NULL, NULL);
140 desc = talloc_array(pool,
char, desc_len + 1);
143 if (
unlikely(ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, 0, desc, NULL) <= 0))
break;
148 ret = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, 0, NULL, NULL);
149 if (ret & ENGINE_CMD_FLAG_NO_INPUT) {
151 }
else if ((ret & ENGINE_CMD_FLAG_NUMERIC) && (ret & ENGINE_CMD_FLAG_STRING)) {
152 flags =
"number and string";
153 }
else if (ret & ENGINE_CMD_FLAG_NUMERIC) {
155 }
else if (ret & ENGINE_CMD_FLAG_STRING) {
158 flags =
"unavailable";
166 talloc_free_children(pool);
181 static inline CC_HINT(always_inline) fr_tls_engine_ctrl_t *tls_engine_ctrl_dup(TALLOC_CTX *ctx,
182 fr_tls_engine_ctrl_t
const *
in)
184 fr_tls_engine_ctrl_t *
n;
186 n = talloc(ctx, fr_tls_engine_ctrl_t);
192 *
n = (fr_tls_engine_ctrl_t){
203 static int _tls_engine_free(tls_engine_t *our_e)
209 if (
unlikely(ENGINE_finish(our_e->e) != 1)) {
210 fr_tls_log(NULL,
"de-init on engine %s failed", our_e->id);
214 if (
unlikely(ENGINE_free(our_e->e) != 1)) {
215 fr_tls_log(NULL,
"free on engine %s failed", our_e->id);
245 int fr_tls_engine_init(ENGINE **e_out,
246 char const *
id,
char const *instance,
247 fr_tls_engine_ctrl_list_t
const *pre_ctrls, fr_tls_engine_ctrl_list_t
const *post_ctrls)
249 tls_engine_t *our_e = NULL;
251 fr_tls_engine_ctrl_t *ctrl = NULL, *
n;
261 tls_engine_t *found = NULL;
263 found =
fr_rb_find(tls_engines, &(tls_engine_t){ .id = id, .instance = instance });
266 instance ?
" (" :
"",
267 instance ? instance :
"",
268 instance ?
") " :
"");
273 e = ENGINE_by_id(
id);
279 if (pre_ctrls)
while ((ctrl =
fr_dlist_next(pre_ctrls, ctrl))) {
282 cmd = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 0,
UNCONST(
void *, ctrl->name), NULL);
289 tls_engine_control_notfound_strerror(e, ctrl->name);
304 flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, 0, NULL, NULL);
305 if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
306 ret = ENGINE_ctrl(e, cmd, 0, NULL, NULL);
310 }
else if (
unlikely((flags & ENGINE_CMD_FLAG_STRING) && (flags & ENGINE_CMD_FLAG_NUMERIC))) {
312 "both numeric and string commands needed for OpenSSL engine controls");
318 }
else if (flags & ENGINE_CMD_FLAG_NUMERIC) {
325 ret = ENGINE_ctrl(e, cmd, vb.vb_int32, NULL, 0);
326 }
else if (flags & ENGINE_CMD_FLAG_STRING) {
327 ret = ENGINE_ctrl(e, cmd, 0,
UNCONST(
void *, ctrl->value), NULL);
338 fr_tls_strerror_printf(
"control %s failed (%i)", ctrl->name, ret);
343 if (
unlikely(ENGINE_init(e) != 1)) {
344 fr_tls_strerror_printf(
"failed initialising engine %s",
id);
348 our_e = talloc(tls_engines, tls_engine_t);
351 *our_e = (tls_engine_t){
356 talloc_set_destructor(our_e, _tls_engine_free);
370 n = tls_engine_ctrl_dup(our_e, ctrl);
382 n = tls_engine_ctrl_dup(our_e, ctrl);
420 int fr_tls_engine(ENGINE **e_out,
char const *
id,
char const *instance,
bool auto_init)
422 tls_engine_t *found = NULL;
428 instance ?
" (" :
"",
429 instance ? instance :
"",
430 instance ?
") " :
"");
435 return fr_tls_engine_init(e_out,
id, instance, NULL, NULL);
439 found =
fr_rb_find(tls_engines, &(tls_engine_t){ .id = id, .instance = instance });
441 if (!auto_init)
goto not_init;
452 void fr_tls_engine_load_builtin(
void)
454 ENGINE_load_builtin_engines();
459 if (!tls_engines || !
fr_rb_find(tls_engines, &(tls_engine_t){ .id =
"rdrand" })) {
462 ENGINE_register_all_RAND();
468 rand_engine = ENGINE_get_default_RAND();
469 if (rand_engine && (strcmp(ENGINE_get_id(rand_engine),
"rdrand") == 0)) {
470 ENGINE_unregister_RAND(rand_engine);
471 ENGINE_finish(rand_engine);
474 ENGINE_register_all_complete();
480 void fr_tls_engine_free_all(
void)
482 TALLOC_FREE(tls_engines);
484 #if OPENSSL_VERSION_NUMBER < 0x10100000L
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define USES_APPLE_DEPRECATED_API
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
@ FR_TYPE_INT32
32 Bit signed integer.
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
The main red black tree structure.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
void talloc_free_data(void *data)
A wrapper that can be passed to tree or hash alloc functions that take a fr_free_t.
#define talloc_get_type_abort_const
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
#define fr_box_strvalue(_val)