26RCSID(
"$Id: d71f2ebb64c2a671da0ab93ac084a56c2ffaaf03 $")
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;
72static 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);
98static 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);
181static 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){
203static int _tls_engine_free(tls_engine_t *our_e)
211 if (
unlikely(ENGINE_finish(our_e->e) != 1)) {
212 fr_tls_log(NULL,
"de-init on engine %s failed", our_e->id);
216 if (
unlikely(ENGINE_free(our_e->e) != 1)) {
217 fr_tls_log(NULL,
"free on engine %s failed", our_e->id);
247int fr_tls_engine_init(ENGINE **e_out,
248 char const *
id,
char const *instance,
249 fr_tls_engine_ctrl_list_t
const *pre_ctrls, fr_tls_engine_ctrl_list_t
const *post_ctrls)
251 tls_engine_t *our_e = NULL;
253 fr_tls_engine_ctrl_t *ctrl = NULL, *
n;
263 tls_engine_t *found = NULL;
265 found =
fr_rb_find(tls_engines, &(tls_engine_t){ .id = id, .instance = instance });
268 instance ?
" (" :
"",
269 instance ? instance :
"",
270 instance ?
") " :
"");
275 e = ENGINE_by_id(
id);
281 if (pre_ctrls)
while ((ctrl =
fr_dlist_next(pre_ctrls, ctrl))) {
284 cmd = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 0,
UNCONST(
void *, ctrl->name), NULL);
291 tls_engine_control_notfound_strerror(e, ctrl->name);
306 flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, 0, NULL, NULL);
307 if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
308 ret = ENGINE_ctrl(e, cmd, 0, NULL, NULL);
312 }
else if (
unlikely((flags & ENGINE_CMD_FLAG_STRING) && (flags & ENGINE_CMD_FLAG_NUMERIC))) {
314 "both numeric and string commands needed for OpenSSL engine controls");
320 }
else if (flags & ENGINE_CMD_FLAG_NUMERIC) {
327 ret = ENGINE_ctrl(e, cmd, vb.vb_int32, NULL, 0);
328 }
else if (flags & ENGINE_CMD_FLAG_STRING) {
329 ret = ENGINE_ctrl(e, cmd, 0,
UNCONST(
void *, ctrl->value), NULL);
340 fr_tls_strerror_printf(
"control %s failed (%i)", ctrl->name, ret);
345 if (
unlikely(ENGINE_init(e) != 1)) {
346 fr_tls_strerror_printf(
"failed initialising engine %s",
id);
350 our_e = talloc(tls_engines, tls_engine_t);
353 *our_e = (tls_engine_t){
358 talloc_set_destructor(our_e, _tls_engine_free);
372 n = tls_engine_ctrl_dup(our_e, ctrl);
384 n = tls_engine_ctrl_dup(our_e, ctrl);
427int fr_tls_engine(ENGINE **e_out,
char const *
id,
char const *instance,
bool auto_init)
429 tls_engine_t *found = NULL;
435 instance ?
" (" :
"",
436 instance ? instance :
"",
437 instance ?
") " :
"");
442 return fr_tls_engine_init(e_out,
id, instance, NULL, NULL);
446 found =
fr_rb_find(tls_engines, &(tls_engine_t){ .id = id, .instance = instance });
448 if (!auto_init)
goto not_init;
459void fr_tls_engine_load_builtin(
void)
461 ENGINE_load_builtin_engines();
466 if (!tls_engines || !
fr_rb_find(tls_engines, &(tls_engine_t){ .id =
"rdrand" })) {
469 ENGINE_register_all_RAND();
475 rand_engine = ENGINE_get_default_RAND();
476 if (!rand_engine)
break;
478 if(strcmp(ENGINE_get_id(rand_engine),
"rdrand") == 0) {
479 ENGINE_unregister_RAND(rand_engine);
485 ENGINE_finish(rand_engine);
486 ENGINE_free(rand_engine);
488 ENGINE_register_all_complete();
494void fr_tls_engine_free_all(
void)
496 TALLOC_FREE(tls_engines);
498#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 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.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
@ FR_TYPE_INT32
32 Bit signed integer.
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
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)