26RCSID(
"$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;    
 
   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)
 
  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);
 
  245int 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);
 
  420int 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;
 
  452void 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();
 
  480void 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 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_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
#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)