//
|
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
|
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
// Copyright 2019 Devolutions <info@devolutions.net>
|
//
|
// This software is supplied under the terms of the MIT License, a
|
// copy of which should be located in the distribution where this
|
// file was obtained (LICENSE.txt). A copy of the license may also be
|
// found online at https://opensource.org/licenses/MIT.
|
//
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
|
#include "core/nng_impl.h"
|
|
#include <nng/supplemental/tls/engine.h>
|
#include <nng/supplemental/tls/tls.h>
|
|
// NNG_TLS_MAX_SEND_SIZE limits the amount of data we will buffer for sending,
|
// exerting back-pressure if this size is exceeded. The 16K is aligned to the
|
// maximum TLS record size.
|
#ifndef NNG_TLS_MAX_SEND_SIZE
|
#define NNG_TLS_MAX_SEND_SIZE 16384
|
#endif
|
|
// NNG_TLS_MAX_RECV_SIZE limits the amount of data we will receive in a single
|
// operation. As we have to buffer data, this drives the size of our
|
// intermediary buffer. The 16K is aligned to the maximum TLS record size.
|
#ifndef NNG_TLX_MAX_RECV_SIZE
|
#define NNG_TLS_MAX_RECV_SIZE 16384
|
#endif
|
|
// This file contains common code for TLS, and is only compiled if we
|
// have TLS configured in the system. In particular, this provides the
|
// parts of TLS support that are invariant relative to different TLS
|
// libraries, such as dialer and listener support.
|
|
#ifdef NNG_SUPP_TLS
|
|
static const nng_tls_engine *tls_engine;
|
static nni_mtx tls_engine_lock;
|
|
struct nng_tls_config {
|
nng_tls_engine_config_ops ops;
|
const nng_tls_engine * engine; // store this so we can verify
|
nni_mtx lock;
|
int ref;
|
int busy;
|
size_t size;
|
|
// ... engine config data follows
|
};
|
|
typedef struct {
|
nng_stream stream;
|
nng_tls_engine_conn_ops ops;
|
nng_tls_config * cfg;
|
const nng_tls_engine * engine;
|
size_t size;
|
nni_aio * user_aio; // user's aio for connect/accept
|
nni_aio conn_aio; // system aio for connect/accept
|
nni_mtx lock;
|
bool closed;
|
bool hs_done;
|
nni_list send_queue;
|
nni_list recv_queue;
|
nng_stream * tcp; // lower level stream
|
nni_aio tcp_send; // lower level send pending
|
nni_aio tcp_recv; // lower level recv pending
|
uint8_t * tcp_send_buf;
|
uint8_t * tcp_recv_buf;
|
size_t tcp_recv_len;
|
size_t tcp_recv_off;
|
bool tcp_recv_pend;
|
bool tcp_send_active;
|
size_t tcp_send_len;
|
size_t tcp_send_head;
|
size_t tcp_send_tail;
|
nni_reap_node reap;
|
|
// ... engine connection data follows
|
} tls_conn;
|
|
static void tls_tcp_send_cb(void *arg);
|
static void tls_tcp_recv_cb(void *arg);
|
static void tls_do_send(tls_conn *);
|
static void tls_do_recv(tls_conn *);
|
static void tls_tcp_send_start(tls_conn *);
|
static void tls_free(void *);
|
static void tls_reap(void *);
|
static int tls_alloc(tls_conn **, nng_tls_config *, nng_aio *);
|
static int tls_start(tls_conn *, nng_stream *);
|
static void tls_tcp_error(tls_conn *, int);
|
|
static nni_reap_list tls_conn_reap_list = {
|
.rl_offset = offsetof(tls_conn, reap),
|
.rl_func = tls_reap,
|
};
|
|
typedef struct {
|
nng_stream_dialer ops;
|
nng_stream_dialer *d; // underlying TCP dialer
|
nng_tls_config * cfg;
|
nni_mtx lk; // protects the config
|
} tls_dialer;
|
|
static void
|
tls_dialer_close(void *arg)
|
{
|
tls_dialer *d = arg;
|
nng_stream_dialer_close(d->d);
|
}
|
|
static void
|
tls_dialer_free(void *arg)
|
{
|
tls_dialer *d;
|
if ((d = arg) != NULL) {
|
nng_stream_dialer_free(d->d);
|
nng_tls_config_free(d->cfg);
|
nni_mtx_fini(&d->lk);
|
NNI_FREE_STRUCT(d);
|
}
|
}
|
|
// For dialing, we need to have our own completion callback, instead of
|
// the user's completion callback.
|
|
static void
|
tls_conn_cb(void *arg)
|
{
|
tls_conn * conn = arg;
|
nng_stream *tcp;
|
int rv;
|
|
if ((rv = nni_aio_result(&conn->conn_aio)) != 0) {
|
nni_aio_finish_error(conn->user_aio, rv);
|
nng_stream_free(&conn->stream);
|
return;
|
}
|
|
tcp = nni_aio_get_output(&conn->conn_aio, 0);
|
|
if ((rv = tls_start(conn, tcp)) != 0) {
|
nni_aio_finish_error(conn->user_aio, rv);
|
nng_stream_free(&conn->stream);
|
return;
|
}
|
|
nni_aio_set_output(conn->user_aio, 0, &conn->stream);
|
nni_aio_finish(conn->user_aio, 0, 0);
|
}
|
|
// Dialer cancel is called when the user has indicated that they no longer
|
// want to wait for the connection to establish.
|
static void
|
tls_conn_cancel(nni_aio *aio, void *arg, int rv)
|
{
|
tls_conn *conn = arg;
|
|
NNI_ARG_UNUSED(aio);
|
|
// Just pass this down. If the connection is already done, this
|
// will have no effect.
|
nni_aio_abort(&conn->conn_aio, rv);
|
}
|
|
static void
|
tls_dialer_dial(void *arg, nng_aio *aio)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
tls_conn * conn;
|
|
if (nni_aio_begin(aio) != 0) {
|
return;
|
}
|
if ((rv = tls_alloc(&conn, d->cfg, aio)) != 0) {
|
nni_aio_finish_error(aio, rv);
|
return;
|
}
|
|
if ((rv = nni_aio_schedule(aio, tls_conn_cancel, conn)) != 0) {
|
nni_aio_finish_error(aio, rv);
|
tls_free(conn);
|
return;
|
}
|
|
nng_stream_dialer_dial(d->d, &conn->conn_aio);
|
}
|
|
static int
|
tls_check_string(const void *v, size_t sz, nni_opt_type t)
|
{
|
switch (t) {
|
case NNI_TYPE_OPAQUE:
|
if (nni_strnlen(v, sz) >= sz) {
|
return (NNG_EINVAL);
|
}
|
return (0);
|
case NNI_TYPE_STRING:
|
// Caller is assumed to pass a good string.
|
return (0);
|
default:
|
return (NNG_EBADTYPE);
|
}
|
}
|
|
static int
|
tls_dialer_set_config(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
int rv;
|
nng_tls_config *cfg;
|
tls_dialer * d = arg;
|
nng_tls_config *old;
|
|
if ((rv = nni_copyin_ptr((void **) &cfg, buf, sz, t)) != 0) {
|
return (rv);
|
}
|
if (cfg == NULL) {
|
return (NNG_EINVAL);
|
}
|
nng_tls_config_hold(cfg);
|
|
nni_mtx_lock(&d->lk);
|
old = d->cfg;
|
d->cfg = cfg;
|
nni_mtx_unlock(&d->lk);
|
|
nng_tls_config_free(old);
|
return (0);
|
}
|
|
static int
|
tls_dialer_get_config(void *arg, void *buf, size_t *szp, nni_type t)
|
{
|
tls_dialer * d = arg;
|
nng_tls_config *cfg;
|
int rv;
|
nni_mtx_lock(&d->lk);
|
if ((cfg = d->cfg) != NULL) {
|
nng_tls_config_hold(cfg);
|
}
|
if ((rv = nni_copyout_ptr(cfg, buf, szp, t)) != 0) {
|
nng_tls_config_free(cfg);
|
}
|
nni_mtx_unlock(&d->lk);
|
return (rv);
|
}
|
|
static int
|
tls_dialer_set_server_name(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&d->lk);
|
rv = nng_tls_config_server_name(d->cfg, buf);
|
nni_mtx_unlock(&d->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_dialer_set_auth_mode(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
int mode;
|
int rv;
|
tls_dialer *d = arg;
|
|
rv = nni_copyin_int(&mode, buf, sz, NNG_TLS_AUTH_MODE_NONE,
|
NNG_TLS_AUTH_MODE_REQUIRED, t);
|
if (rv == 0) {
|
nni_mtx_lock(&d->lk);
|
rv = nng_tls_config_auth_mode(d->cfg, mode);
|
nni_mtx_unlock(&d->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_dialer_set_ca_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&d->lk);
|
rv = nng_tls_config_ca_file(d->cfg, buf);
|
nni_mtx_unlock(&d->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_dialer_set_cert_key_file(
|
void *arg, const void *buf, size_t sz, nni_opt_type t)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&d->lk);
|
rv = nng_tls_config_cert_key_file(d->cfg, buf, NULL);
|
nni_mtx_unlock(&d->lk);
|
}
|
return (rv);
|
}
|
|
static const nni_option tls_dialer_opts[] = {
|
{
|
.o_name = NNG_OPT_TLS_CONFIG,
|
.o_get = tls_dialer_get_config,
|
.o_set = tls_dialer_set_config,
|
},
|
{
|
.o_name = NNG_OPT_TLS_SERVER_NAME,
|
.o_set = tls_dialer_set_server_name,
|
},
|
{
|
.o_name = NNG_OPT_TLS_CA_FILE,
|
.o_set = tls_dialer_set_ca_file,
|
},
|
{
|
.o_name = NNG_OPT_TLS_CERT_KEY_FILE,
|
.o_set = tls_dialer_set_cert_key_file,
|
},
|
{
|
.o_name = NNG_OPT_TLS_AUTH_MODE,
|
.o_set = tls_dialer_set_auth_mode,
|
},
|
{
|
.o_name = NULL,
|
},
|
};
|
|
static int
|
tls_dialer_get(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
|
rv = nni_stream_dialer_get(d->d, name, buf, szp, t);
|
if (rv == NNG_ENOTSUP) {
|
rv = nni_getopt(tls_dialer_opts, name, d, buf, szp, t);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_dialer_set(
|
void *arg, const char *name, const void *buf, size_t sz, nni_type t)
|
{
|
tls_dialer *d = arg;
|
int rv;
|
|
rv = nni_stream_dialer_set(d->d, name, buf, sz, t);
|
if (rv == NNG_ENOTSUP) {
|
rv = nni_setopt(tls_dialer_opts, name, d, buf, sz, t);
|
}
|
return (rv);
|
}
|
|
int
|
nni_tls_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
|
{
|
tls_dialer *d;
|
int rv;
|
nng_url my_url;
|
|
memcpy(&my_url, url, sizeof(my_url));
|
if (strncmp(my_url.u_scheme, "tls+", 4) == 0) {
|
my_url.u_scheme += 4;
|
}
|
|
if ((rv = nni_init()) != 0) {
|
return (rv);
|
}
|
if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
|
return (NNG_ENOMEM);
|
}
|
nni_mtx_init(&d->lk);
|
|
if ((rv = nng_stream_dialer_alloc_url(&d->d, &my_url)) != 0) {
|
nni_mtx_fini(&d->lk);
|
NNI_FREE_STRUCT(d);
|
return (rv);
|
}
|
if ((rv = nng_tls_config_alloc(&d->cfg, NNG_TLS_MODE_CLIENT)) != 0) {
|
nng_stream_dialer_free(d->d);
|
nni_mtx_fini(&d->lk);
|
NNI_FREE_STRUCT(d);
|
return (rv);
|
}
|
|
// Set the expected outbound hostname
|
nng_tls_config_server_name(d->cfg, url->u_hostname);
|
|
d->ops.sd_close = tls_dialer_close;
|
d->ops.sd_free = tls_dialer_free;
|
d->ops.sd_dial = tls_dialer_dial;
|
d->ops.sd_get = tls_dialer_get;
|
d->ops.sd_set = tls_dialer_set;
|
*dp = (void *) d;
|
return (rv);
|
}
|
|
typedef struct {
|
nng_stream_listener ops;
|
nng_stream_listener *l;
|
nng_tls_config * cfg;
|
nni_mtx lk;
|
} tls_listener;
|
|
static void
|
tls_listener_close(void *arg)
|
{
|
tls_listener *l = arg;
|
nng_stream_listener_close(l->l);
|
}
|
|
static void
|
tls_listener_free(void *arg)
|
{
|
tls_listener *l;
|
if ((l = arg) != NULL) {
|
tls_listener_close(l);
|
nng_tls_config_free(l->cfg);
|
nng_stream_listener_free(l->l);
|
nni_mtx_fini(&l->lk);
|
NNI_FREE_STRUCT(l);
|
}
|
}
|
|
static int
|
tls_listener_listen(void *arg)
|
{
|
tls_listener *l = arg;
|
return (nng_stream_listener_listen(l->l));
|
}
|
|
static void
|
tls_listener_accept(void *arg, nng_aio *aio)
|
{
|
tls_listener *l = arg;
|
int rv;
|
tls_conn * conn;
|
|
if (nni_aio_begin(aio) != 0) {
|
return;
|
}
|
if ((rv = tls_alloc(&conn, l->cfg, aio)) != 0) {
|
nni_aio_finish_error(aio, rv);
|
return;
|
}
|
|
if ((rv = nni_aio_schedule(aio, tls_conn_cancel, conn)) != 0) {
|
nni_aio_finish_error(aio, rv);
|
tls_free(conn);
|
return;
|
}
|
|
nng_stream_listener_accept(l->l, &conn->conn_aio);
|
}
|
|
static int
|
tls_listener_set_config(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
int rv;
|
nng_tls_config *cfg;
|
tls_listener * l = arg;
|
nng_tls_config *old;
|
|
if ((rv = nni_copyin_ptr((void **) &cfg, buf, sz, t)) != 0) {
|
return (rv);
|
}
|
if (cfg == NULL) {
|
return (NNG_EINVAL);
|
}
|
|
nng_tls_config_hold(cfg);
|
|
nni_mtx_lock(&l->lk);
|
old = l->cfg;
|
l->cfg = cfg;
|
nni_mtx_unlock(&l->lk);
|
|
nng_tls_config_free(old);
|
|
return (0);
|
}
|
|
static int
|
tls_listener_get_config(void *arg, void *buf, size_t *szp, nni_type t)
|
{
|
tls_listener * l = arg;
|
nng_tls_config *cfg;
|
int rv;
|
nni_mtx_lock(&l->lk);
|
if ((cfg = l->cfg) != NULL) {
|
nng_tls_config_hold(cfg);
|
}
|
if ((rv = nni_copyout_ptr(cfg, buf, szp, t)) != 0) {
|
nng_tls_config_free(cfg);
|
}
|
nni_mtx_unlock(&l->lk);
|
return (rv);
|
}
|
|
static int
|
tls_listener_set_server_name(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
tls_listener *l = arg;
|
int rv;
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&l->lk);
|
rv = nng_tls_config_server_name(l->cfg, buf);
|
nni_mtx_unlock(&l->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_listener_set_auth_mode(void *arg, const void *buf, size_t sz, nni_type t)
|
{
|
int mode;
|
int rv;
|
tls_listener *l = arg;
|
|
rv = nni_copyin_int(&mode, buf, sz, NNG_TLS_AUTH_MODE_NONE,
|
NNG_TLS_AUTH_MODE_REQUIRED, t);
|
if (rv == 0) {
|
nni_mtx_lock(&l->lk);
|
rv = nng_tls_config_auth_mode(l->cfg, mode);
|
nni_mtx_unlock(&l->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_listener_set_ca_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
|
{
|
tls_listener *l = arg;
|
int rv;
|
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&l->lk);
|
rv = nng_tls_config_ca_file(l->cfg, buf);
|
nni_mtx_unlock(&l->lk);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_listener_set_cert_key_file(
|
void *arg, const void *buf, size_t sz, nni_opt_type t)
|
{
|
tls_listener *l = arg;
|
int rv;
|
|
if ((rv = tls_check_string(buf, sz, t)) == 0) {
|
nni_mtx_lock(&l->lk);
|
rv = nng_tls_config_cert_key_file(l->cfg, buf, NULL);
|
nni_mtx_unlock(&l->lk);
|
}
|
return (rv);
|
}
|
|
static const nni_option tls_listener_opts[] = {
|
{
|
.o_name = NNG_OPT_TLS_CONFIG,
|
.o_get = tls_listener_get_config,
|
.o_set = tls_listener_set_config,
|
},
|
{
|
.o_name = NNG_OPT_TLS_SERVER_NAME,
|
.o_set = tls_listener_set_server_name,
|
},
|
{
|
.o_name = NNG_OPT_TLS_CA_FILE,
|
.o_set = tls_listener_set_ca_file,
|
},
|
{
|
.o_name = NNG_OPT_TLS_CERT_KEY_FILE,
|
.o_set = tls_listener_set_cert_key_file,
|
},
|
{
|
.o_name = NNG_OPT_TLS_AUTH_MODE,
|
.o_set = tls_listener_set_auth_mode,
|
},
|
{
|
.o_name = NULL,
|
},
|
};
|
|
static int
|
tls_listener_get(
|
void *arg, const char *name, void *buf, size_t *szp, nni_type t)
|
{
|
int rv;
|
tls_listener *l = arg;
|
|
rv = nni_stream_listener_get(l->l, name, buf, szp, t);
|
if (rv == NNG_ENOTSUP) {
|
rv = nni_getopt(tls_listener_opts, name, l, buf, szp, t);
|
}
|
return (rv);
|
}
|
|
static int
|
tls_listener_set(
|
void *arg, const char *name, const void *buf, size_t sz, nni_type t)
|
{
|
int rv;
|
tls_listener *l = arg;
|
|
rv = nni_stream_listener_set(l->l, name, buf, sz, t);
|
if (rv == NNG_ENOTSUP) {
|
rv = nni_setopt(tls_listener_opts, name, l, buf, sz, t);
|
}
|
return (rv);
|
}
|
|
int
|
nni_tls_listener_alloc(nng_stream_listener **lp, const nng_url *url)
|
{
|
tls_listener *l;
|
int rv;
|
nng_url my_url;
|
|
memcpy(&my_url, url, sizeof(my_url));
|
|
if (strncmp(my_url.u_scheme, "tls+", 4) == 0) {
|
my_url.u_scheme += 4;
|
}
|
|
if ((rv = nni_init()) != 0) {
|
return (rv);
|
}
|
if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
|
return (NNG_ENOMEM);
|
}
|
nni_mtx_init(&l->lk);
|
|
if ((rv = nng_stream_listener_alloc_url(&l->l, &my_url)) != 0) {
|
nni_mtx_fini(&l->lk);
|
NNI_FREE_STRUCT(l);
|
return (rv);
|
}
|
if ((rv = nng_tls_config_alloc(&l->cfg, NNG_TLS_MODE_SERVER)) != 0) {
|
nng_stream_listener_free(l->l);
|
nni_mtx_fini(&l->lk);
|
NNI_FREE_STRUCT(l);
|
return (rv);
|
}
|
l->ops.sl_free = tls_listener_free;
|
l->ops.sl_close = tls_listener_close;
|
l->ops.sl_accept = tls_listener_accept;
|
l->ops.sl_listen = tls_listener_listen;
|
l->ops.sl_get = tls_listener_get;
|
l->ops.sl_set = tls_listener_set;
|
*lp = (void *) l;
|
return (0);
|
}
|
|
static void
|
tls_cancel(nni_aio *aio, void *arg, int rv)
|
{
|
tls_conn *conn = arg;
|
nni_mtx_lock(&conn->lock);
|
if (aio == nni_list_first(&conn->recv_queue)) {
|
nni_aio_abort(&conn->tcp_recv, rv);
|
} else if (aio == nni_list_first(&conn->send_queue)) {
|
nni_aio_abort(&conn->tcp_send, rv);
|
} else if (nni_aio_list_active(aio)) {
|
nni_aio_list_remove(aio);
|
nni_aio_finish_error(aio, rv);
|
}
|
nni_mtx_unlock(&conn->lock);
|
}
|
|
// tls_send implements the upper layer stream send operation.
|
static void
|
tls_send(void *arg, nni_aio *aio)
|
{
|
int rv;
|
tls_conn *conn = arg;
|
|
if (nni_aio_begin(aio) != 0) {
|
return;
|
}
|
nni_mtx_lock(&conn->lock);
|
if (conn->closed) {
|
nni_mtx_unlock(&conn->lock);
|
nni_aio_finish_error(aio, NNG_ECLOSED);
|
return;
|
}
|
if ((rv = nni_aio_schedule(aio, tls_cancel, conn)) != 0) {
|
nni_mtx_unlock(&conn->lock);
|
nni_aio_finish_error(aio, rv);
|
return;
|
}
|
nni_list_append(&conn->send_queue, aio);
|
tls_do_send(conn);
|
nni_mtx_unlock(&conn->lock);
|
}
|
|
static void
|
tls_recv(void *arg, nni_aio *aio)
|
{
|
int rv;
|
tls_conn *conn = arg;
|
|
if (nni_aio_begin(aio) != 0) {
|
return;
|
}
|
nni_mtx_lock(&conn->lock);
|
if (conn->closed) {
|
nni_mtx_unlock(&conn->lock);
|
nni_aio_finish_error(aio, NNG_ECLOSED);
|
return;
|
}
|
if ((rv = nni_aio_schedule(aio, tls_cancel, conn)) != 0) {
|
nni_mtx_unlock(&conn->lock);
|
nni_aio_finish_error(aio, rv);
|
return;
|
}
|
|
nni_list_append(&conn->recv_queue, aio);
|
tls_do_recv(conn);
|
nni_mtx_unlock(&conn->lock);
|
}
|
|
static void
|
tls_close(void *arg)
|
{
|
tls_conn *conn = arg;
|
|
nni_mtx_lock(&conn->lock);
|
conn->ops.close((void *) (conn + 1));
|
tls_tcp_error(conn, NNG_ECLOSED);
|
nni_mtx_unlock(&conn->lock);
|
nng_stream_close(conn->tcp);
|
}
|
|
static int
|
tls_get_verified(void *arg, void *buf, size_t *szp, nni_type t)
|
{
|
tls_conn *conn = arg;
|
bool v;
|
|
nni_mtx_lock(&conn->lock);
|
v = conn->ops.verified((void *) (conn + 1));
|
nni_mtx_unlock(&conn->lock);
|
return (nni_copyout_bool(v, buf, szp, t));
|
}
|
|
static const nni_option tls_options[] = {
|
{
|
.o_name = NNG_OPT_TLS_VERIFIED,
|
.o_get = tls_get_verified,
|
},
|
{
|
.o_name = NULL,
|
},
|
};
|
|
static int
|
tls_set(void *arg, const char *name, const void *buf, size_t sz, nni_type t)
|
{
|
tls_conn * conn = arg;
|
int rv;
|
nng_stream *tcp;
|
|
tcp = (conn != NULL) ? conn->tcp : NULL;
|
|
if ((rv = nni_stream_set(tcp, name, buf, sz, t)) != NNG_ENOTSUP) {
|
return (rv);
|
}
|
return (nni_setopt(tls_options, name, conn, buf, sz, t));
|
}
|
|
static int
|
tls_get(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
|
{
|
tls_conn *conn = arg;
|
int rv;
|
|
if ((rv = nni_stream_get(conn->tcp, name, buf, szp, t)) !=
|
NNG_ENOTSUP) {
|
return (rv);
|
}
|
return (nni_getopt(tls_options, name, conn, buf, szp, t));
|
}
|
|
static int
|
tls_alloc(tls_conn **conn_p, nng_tls_config *cfg, nng_aio *user_aio)
|
{
|
tls_conn * conn;
|
const nng_tls_engine *eng;
|
size_t size;
|
|
eng = cfg->engine;
|
|
size = NNI_ALIGN_UP(sizeof(*conn)) + eng->conn_ops->size;
|
|
if ((conn = nni_zalloc(size)) == NULL) {
|
return (NNG_ENOMEM);
|
}
|
if (((conn->tcp_send_buf = nni_alloc(NNG_TLS_MAX_SEND_SIZE)) ==
|
NULL) ||
|
((conn->tcp_recv_buf = nni_alloc(NNG_TLS_MAX_RECV_SIZE)) ==
|
NULL)) {
|
tls_free(conn);
|
return (NNG_ENOMEM);
|
}
|
conn->size = size;
|
conn->ops = *eng->conn_ops;
|
conn->engine = eng;
|
conn->user_aio = user_aio;
|
conn->cfg = cfg;
|
|
nni_aio_init(&conn->conn_aio, tls_conn_cb, conn);
|
nni_aio_init(&conn->tcp_recv, tls_tcp_recv_cb, conn);
|
nni_aio_init(&conn->tcp_send, tls_tcp_send_cb, conn);
|
nni_aio_list_init(&conn->send_queue);
|
nni_aio_list_init(&conn->recv_queue);
|
nni_mtx_init(&conn->lock);
|
nni_aio_set_timeout(&conn->tcp_send, NNG_DURATION_INFINITE);
|
nni_aio_set_timeout(&conn->tcp_recv, NNG_DURATION_INFINITE);
|
|
conn->stream.s_close = tls_close;
|
conn->stream.s_free = tls_free;
|
conn->stream.s_send = tls_send;
|
conn->stream.s_recv = tls_recv;
|
conn->stream.s_get = tls_get;
|
conn->stream.s_set = tls_set;
|
|
nng_tls_config_hold(cfg);
|
*conn_p = conn;
|
return (0);
|
}
|
|
static void
|
tls_reap(void *arg)
|
{
|
tls_conn *conn = arg;
|
|
// Shut it all down first. We should be freed.
|
if (conn->tcp != NULL) {
|
nng_stream_close(conn->tcp);
|
}
|
nni_aio_stop(&conn->conn_aio);
|
nni_aio_stop(&conn->tcp_send);
|
nni_aio_stop(&conn->tcp_recv);
|
|
conn->ops.fini((void *) (conn + 1));
|
nni_aio_fini(&conn->conn_aio);
|
nni_aio_fini(&conn->tcp_send);
|
nni_aio_fini(&conn->tcp_recv);
|
nng_stream_free(conn->tcp);
|
if (conn->cfg != NULL) {
|
nng_tls_config_free(conn->cfg); // this drops our hold on it
|
}
|
if (conn->tcp_send_buf != NULL) {
|
nni_free(conn->tcp_send_buf, NNG_TLS_MAX_SEND_SIZE);
|
}
|
if (conn->tcp_recv_buf != NULL) {
|
nni_free(conn->tcp_recv_buf, NNG_TLS_MAX_RECV_SIZE);
|
}
|
NNI_FREE_STRUCT(conn);
|
}
|
|
static void
|
tls_free(void *arg)
|
{
|
tls_conn *conn = arg;
|
|
nni_reap(&tls_conn_reap_list, conn);
|
}
|
|
static int
|
tls_start(tls_conn *conn, nng_stream *tcp)
|
{
|
int rv;
|
|
conn->tcp = tcp;
|
rv = conn->ops.init(
|
(void *) (conn + 1), conn, (void *) (conn->cfg + 1));
|
return (rv);
|
}
|
|
static void
|
tls_tcp_error(tls_conn *conn, int rv)
|
{
|
// An error here is fatal. Shut it all down.
|
nni_aio *aio;
|
nng_stream_close(conn->tcp);
|
nni_aio_close(&conn->tcp_send);
|
nni_aio_close(&conn->tcp_recv);
|
while (((aio = nni_list_first(&conn->send_queue)) != NULL) ||
|
((aio = nni_list_first(&conn->recv_queue)) != NULL)) {
|
nni_aio_list_remove(aio);
|
nni_aio_finish_error(aio, rv);
|
}
|
}
|
|
static bool
|
tls_do_handshake(tls_conn *conn)
|
{
|
int rv;
|
if (conn->hs_done) {
|
return (true);
|
}
|
rv = conn->ops.handshake((void *) (conn + 1));
|
if (rv == NNG_EAGAIN) {
|
// We need more data.
|
return (false);
|
}
|
if (rv == 0) {
|
conn->hs_done = true;
|
return (true);
|
}
|
tls_tcp_error(conn, rv);
|
return (true);
|
}
|
|
static void
|
tls_do_recv(tls_conn *conn)
|
{
|
nni_aio *aio;
|
|
while ((aio = nni_list_first(&conn->recv_queue)) != NULL) {
|
uint8_t *buf = NULL;
|
size_t len = 0;
|
nni_iov *iov;
|
unsigned nio;
|
int rv;
|
|
nni_aio_get_iov(aio, &nio, &iov);
|
|
for (unsigned i = 0; i < nio; i++) {
|
if (iov[i].iov_len != 0) {
|
buf = iov[i].iov_buf;
|
len = iov[i].iov_len;
|
break;
|
}
|
}
|
if (len == 0 || buf == NULL) {
|
// Caller has asked to receive "nothing".
|
nni_aio_list_remove(aio);
|
nni_aio_finish_error(aio, NNG_EINVAL);
|
continue;
|
}
|
|
rv = conn->ops.recv((void *) (conn + 1), buf, &len);
|
if (rv == NNG_EAGAIN) {
|
// Nothing more we can do, the engine doesn't
|
// have anything else for us (yet).
|
return;
|
}
|
|
// Unlike the send side, we want to return back to the
|
// caller as *soon* as we have some data.
|
nni_aio_list_remove(aio);
|
|
if (rv != 0) {
|
nni_aio_finish_error(aio, rv);
|
} else {
|
nni_aio_finish(aio, 0, len);
|
}
|
}
|
}
|
|
// tls_do_send attempts to send user data.
|
static void
|
tls_do_send(tls_conn *conn)
|
{
|
nni_aio *aio;
|
|
while ((aio = nni_list_first(&conn->send_queue)) != NULL) {
|
uint8_t *buf = NULL;
|
size_t len = 0;
|
nni_iov *iov;
|
unsigned nio;
|
int rv;
|
|
nni_aio_get_iov(aio, &nio, &iov);
|
|
for (unsigned i = 0; i < nio; i++) {
|
if (iov[i].iov_len != 0) {
|
buf = iov[i].iov_buf;
|
len = iov[i].iov_len;
|
break;
|
}
|
}
|
if (len == 0 || buf == NULL) {
|
nni_aio_list_remove(aio);
|
// Presumably this means we've completed this
|
// one, lets preserve the count, and move to the
|
// next.
|
nni_aio_finish(aio, 0, nni_aio_count(aio));
|
continue;
|
}
|
|
// Ask the engine to send.
|
rv = conn->ops.send((void *) (conn + 1), buf, &len);
|
if (rv == NNG_EAGAIN) {
|
// Can't send any more, wait for callback.
|
return;
|
}
|
|
if (rv != 0) {
|
nni_aio_list_remove(aio);
|
nni_aio_finish_error(aio, rv);
|
} else {
|
nni_aio_list_remove(aio);
|
nni_aio_finish(aio, 0, len);
|
}
|
}
|
}
|
|
static void
|
tls_tcp_send_cb(void *arg)
|
{
|
tls_conn *conn = arg;
|
nng_aio * aio = &conn->tcp_send;
|
int rv;
|
size_t count;
|
|
nni_mtx_lock(&conn->lock);
|
conn->tcp_send_active = false;
|
|
if ((rv = nni_aio_result(aio)) != 0) {
|
tls_tcp_error(conn, rv);
|
nni_mtx_unlock(&conn->lock);
|
return;
|
}
|
|
count = nni_aio_count(aio);
|
NNI_ASSERT(count <= conn->tcp_send_len);
|
conn->tcp_send_len -= count;
|
conn->tcp_send_tail += count;
|
conn->tcp_send_tail %= NNG_TLS_MAX_SEND_SIZE;
|
tls_tcp_send_start(conn);
|
|
if (tls_do_handshake(conn)) {
|
tls_do_send(conn);
|
tls_do_recv(conn);
|
}
|
|
nni_mtx_unlock(&conn->lock);
|
}
|
|
static void
|
tls_tcp_recv_cb(void *arg)
|
{
|
tls_conn *conn = arg;
|
nni_aio * aio = &conn->tcp_recv;
|
int rv;
|
|
nni_mtx_lock(&conn->lock);
|
|
conn->tcp_recv_pend = false;
|
if ((rv = nni_aio_result(aio)) != 0) {
|
tls_tcp_error(conn, rv);
|
nni_mtx_unlock(&conn->lock);
|
return;
|
}
|
|
NNI_ASSERT(conn->tcp_recv_len == 0);
|
NNI_ASSERT(conn->tcp_recv_off == 0);
|
conn->tcp_recv_len = nni_aio_count(aio);
|
|
if (tls_do_handshake(conn)) {
|
tls_do_recv(conn);
|
tls_do_send(conn);
|
}
|
|
nni_mtx_unlock(&conn->lock);
|
}
|
|
static void
|
tls_tcp_recv_start(tls_conn *conn)
|
{
|
nng_iov iov;
|
|
if (conn->tcp_recv_len != 0) {
|
// We already have data in the buffer.
|
return;
|
}
|
if (conn->tcp_recv_pend) {
|
// Already have a receive in flight.
|
return;
|
}
|
conn->tcp_recv_off = 0;
|
iov.iov_len = NNG_TLS_MAX_RECV_SIZE;
|
iov.iov_buf = conn->tcp_recv_buf;
|
|
conn->tcp_recv_pend = true;
|
nng_aio_set_iov(&conn->tcp_recv, 1, &iov);
|
|
nng_stream_recv(conn->tcp, &conn->tcp_recv);
|
}
|
|
static void
|
tls_tcp_send_start(tls_conn *conn)
|
{
|
nni_iov iov[2];
|
unsigned nio = 0;
|
size_t len;
|
size_t tail;
|
size_t head;
|
|
if (conn->tcp_send_active) {
|
return;
|
}
|
if (conn->tcp_send_len == 0) {
|
return;
|
}
|
len = conn->tcp_send_len;
|
head = conn->tcp_send_head;
|
tail = conn->tcp_send_tail;
|
|
while (len > 0) {
|
size_t cnt;
|
NNI_ASSERT(nio < 2);
|
if (tail < head) {
|
cnt = head - tail;
|
} else {
|
cnt = NNG_TLS_MAX_SEND_SIZE - tail;
|
}
|
if (cnt > len) {
|
cnt = len;
|
}
|
iov[nio].iov_buf = conn->tcp_send_buf + tail;
|
iov[nio].iov_len = cnt;
|
len -= cnt;
|
tail += cnt;
|
tail %= NNG_TLS_MAX_SEND_SIZE;
|
nio++;
|
}
|
conn->tcp_send_active = true;
|
nni_aio_set_iov(&conn->tcp_send, nio, iov);
|
nng_stream_send(conn->tcp, &conn->tcp_send);
|
}
|
|
int
|
nng_tls_engine_send(void *arg, const uint8_t *buf, size_t *szp)
|
{
|
tls_conn *conn = arg;
|
size_t len = *szp;
|
size_t head = conn->tcp_send_head;
|
size_t tail = conn->tcp_send_tail;
|
size_t space;
|
size_t cnt;
|
|
space = NNG_TLS_MAX_SEND_SIZE - conn->tcp_send_len;
|
|
if (space == 0) {
|
return (NNG_EAGAIN);
|
}
|
|
if (conn->closed) {
|
return (NNG_ECLOSED);
|
}
|
|
if (len > space) {
|
len = space;
|
}
|
|
// We are committed at this point to sending out len bytes.
|
// Update this now, so that we can use len to update.
|
*szp = len;
|
conn->tcp_send_len += len;
|
NNI_ASSERT(conn->tcp_send_len <= NNG_TLS_MAX_SEND_SIZE);
|
|
while (len > 0) {
|
if (head >= tail) {
|
cnt = NNG_TLS_MAX_SEND_SIZE - head;
|
} else {
|
cnt = tail - head;
|
}
|
if (cnt > len) {
|
cnt = len;
|
}
|
|
memcpy(conn->tcp_send_buf + head, buf, cnt);
|
buf += cnt;
|
head += cnt;
|
head %= NNG_TLS_MAX_SEND_SIZE;
|
len -= cnt;
|
}
|
|
conn->tcp_send_head = head;
|
|
tls_tcp_send_start(conn);
|
return (0);
|
}
|
|
int
|
nng_tls_engine_recv(void *arg, uint8_t *buf, size_t *szp)
|
{
|
tls_conn *conn = arg;
|
size_t len = *szp;
|
|
if (conn->closed) {
|
return (NNG_ECLOSED);
|
}
|
if (conn->tcp_recv_len == 0) {
|
tls_tcp_recv_start(conn);
|
return (NNG_EAGAIN);
|
}
|
if (len > conn->tcp_recv_len) {
|
len = conn->tcp_recv_len;
|
}
|
memcpy(buf, conn->tcp_recv_buf + conn->tcp_recv_off, len);
|
conn->tcp_recv_off += len;
|
conn->tcp_recv_len -= len;
|
|
// If we still have data left in the buffer, then the following
|
// call is a no-op.
|
tls_tcp_recv_start(conn);
|
|
*szp = len;
|
return (0);
|
}
|
|
int
|
nng_tls_config_cert_key_file(
|
nng_tls_config *cfg, const char *path, const char *pass)
|
{
|
int rv;
|
void * data;
|
size_t size;
|
char * pem;
|
|
if ((rv = nni_file_get(path, &data, &size)) != 0) {
|
return (rv);
|
}
|
if ((pem = nni_zalloc(size + 1)) == NULL) {
|
nni_free(data, size);
|
return (NNG_ENOMEM);
|
}
|
memcpy(pem, data, size);
|
nni_free(data, size);
|
rv = nng_tls_config_own_cert(cfg, pem, pem, pass);
|
nni_free(pem, size + 1);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_ca_file(nng_tls_config *cfg, const char *path)
|
{
|
int rv;
|
void * data;
|
size_t size;
|
char * pem;
|
|
if ((rv = nni_file_get(path, &data, &size)) != 0) {
|
return (rv);
|
}
|
if ((pem = nni_zalloc(size + 1)) == NULL) {
|
nni_free(data, size);
|
return (NNG_ENOMEM);
|
}
|
memcpy(pem, data, size);
|
nni_free(data, size);
|
if (strstr(pem, "-----BEGIN X509 CRL-----") != NULL) {
|
rv = nng_tls_config_ca_chain(cfg, pem, pem);
|
} else {
|
rv = nng_tls_config_ca_chain(cfg, pem, NULL);
|
}
|
nni_free(pem, size + 1);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_version(
|
nng_tls_config *cfg, nng_tls_version min_ver, nng_tls_version max_ver)
|
{
|
int rv;
|
|
nni_mtx_lock(&cfg->lock);
|
if (cfg->busy != 0) {
|
rv = NNG_EBUSY;
|
} else {
|
rv = cfg->ops.version((void *) (cfg + 1), min_ver, max_ver);
|
}
|
nni_mtx_unlock(&cfg->lock);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_server_name(nng_tls_config *cfg, const char *name)
|
{
|
int rv;
|
|
nni_mtx_lock(&cfg->lock);
|
if (cfg->busy != 0) {
|
rv = NNG_EBUSY;
|
} else {
|
rv = cfg->ops.server((void *) (cfg + 1), name);
|
}
|
nni_mtx_unlock(&cfg->lock);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_ca_chain(
|
nng_tls_config *cfg, const char *certs, const char *crl)
|
{
|
int rv;
|
|
nni_mtx_lock(&cfg->lock);
|
if (cfg->busy != 0) {
|
rv = NNG_EBUSY;
|
} else {
|
rv = cfg->ops.ca_chain((void *) (cfg + 1), certs, crl);
|
}
|
nni_mtx_unlock(&cfg->lock);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_own_cert(
|
nng_tls_config *cfg, const char *cert, const char *key, const char *pass)
|
{
|
int rv;
|
nni_mtx_lock(&cfg->lock);
|
if (cfg->busy != 0) {
|
rv = NNG_EBUSY;
|
} else {
|
rv = cfg->ops.own_cert((void *) (cfg + 1), cert, key, pass);
|
}
|
nni_mtx_unlock(&cfg->lock);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_auth_mode(nng_tls_config *cfg, nng_tls_auth_mode mode)
|
{
|
int rv;
|
|
nni_mtx_lock(&cfg->lock);
|
if (cfg->busy != 0) {
|
rv = NNG_EBUSY;
|
} else {
|
rv = cfg->ops.auth((void *) (cfg + 1), mode);
|
}
|
nni_mtx_unlock(&cfg->lock);
|
return (rv);
|
}
|
|
int
|
nng_tls_config_alloc(nng_tls_config **cfg_p, nng_tls_mode mode)
|
{
|
nng_tls_config * cfg;
|
const nng_tls_engine *eng;
|
size_t size;
|
int rv;
|
|
if ((rv = nni_init()) != 0) {
|
return (rv);
|
}
|
|
nni_mtx_lock(&tls_engine_lock);
|
eng = tls_engine;
|
nni_mtx_unlock(&tls_engine_lock);
|
|
if (eng == NULL) {
|
return (NNG_ENOTSUP);
|
}
|
|
size = NNI_ALIGN_UP(sizeof(*cfg)) + eng->config_ops->size;
|
|
if ((cfg = nni_zalloc(size)) == NULL) {
|
return (NNG_ENOMEM);
|
}
|
|
cfg->ops = *eng->config_ops;
|
cfg->size = size;
|
cfg->engine = eng;
|
cfg->ref = 1;
|
cfg->busy = 0;
|
nni_mtx_init(&cfg->lock);
|
|
if ((rv = cfg->ops.init((void *) (cfg + 1), mode)) != 0) {
|
nni_free(cfg, cfg->size);
|
return (rv);
|
}
|
*cfg_p = cfg;
|
return (0);
|
}
|
|
void
|
nng_tls_config_free(nng_tls_config *cfg)
|
{
|
nni_mtx_lock(&cfg->lock);
|
cfg->ref--;
|
if (cfg->ref != 0) {
|
nni_mtx_unlock(&cfg->lock);
|
return;
|
}
|
nni_mtx_unlock(&cfg->lock);
|
nni_mtx_fini(&cfg->lock);
|
cfg->ops.fini((void *) (cfg + 1));
|
nni_free(cfg, cfg->size);
|
}
|
|
void
|
nng_tls_config_hold(nng_tls_config *cfg)
|
{
|
nni_mtx_lock(&cfg->lock);
|
cfg->ref++;
|
nni_mtx_unlock(&cfg->lock);
|
}
|
|
const char *
|
nng_tls_engine_name(void)
|
{
|
const nng_tls_engine *eng;
|
|
nni_init();
|
nni_mtx_lock(&tls_engine_lock);
|
eng = tls_engine;
|
nni_mtx_unlock(&tls_engine_lock);
|
|
return (eng == NULL ? "none" : eng->name);
|
}
|
|
const char *
|
nng_tls_engine_description(void)
|
{
|
const nng_tls_engine *eng;
|
|
nni_init();
|
nni_mtx_lock(&tls_engine_lock);
|
eng = tls_engine;
|
nni_mtx_unlock(&tls_engine_lock);
|
|
return (eng == NULL ? "" : eng->description);
|
}
|
|
bool
|
nng_tls_engine_fips_mode(void)
|
{
|
const nng_tls_engine *eng;
|
|
nni_init();
|
nni_mtx_lock(&tls_engine_lock);
|
eng = tls_engine;
|
nni_mtx_unlock(&tls_engine_lock);
|
|
return (eng == NULL ? false : eng->fips_mode);
|
}
|
|
int
|
nng_tls_engine_register(const nng_tls_engine *engine)
|
{
|
if (engine->version != NNG_TLS_ENGINE_VERSION) {
|
return (NNG_ENOTSUP);
|
}
|
nni_mtx_lock(&tls_engine_lock);
|
tls_engine = engine;
|
nni_mtx_unlock(&tls_engine_lock);
|
return (0);
|
}
|
|
#ifdef NNG_TLS_ENGINE_INIT
|
extern int NNG_TLS_ENGINE_INIT(void);
|
#else
|
static int
|
NNG_TLS_ENGINE_INIT(void)
|
{
|
return (0);
|
}
|
#endif
|
|
#ifdef NNG_TLS_ENGINE_FINI
|
extern void NNG_TLS_ENGINE_FINI(void);
|
#else
|
static void
|
NNG_TLS_ENGINE_FINI(void)
|
{
|
}
|
#endif
|
|
int
|
nni_tls_sys_init(void)
|
{
|
int rv;
|
nni_mtx_init(&tls_engine_lock);
|
tls_engine = NULL;
|
|
rv = NNG_TLS_ENGINE_INIT();
|
if (rv != 0) {
|
nni_mtx_fini(&tls_engine_lock);
|
return (rv);
|
}
|
return (0);
|
}
|
|
void
|
nni_tls_sys_fini(void)
|
{
|
nni_reap_drain();
|
NNG_TLS_ENGINE_FINI();
|
}
|
|
#else // NNG_SUPP_TLS
|
|
// Provide stubs for the case where TLS is not enabled.
|
void
|
nni_tls_config_fini(nng_tls_config *cfg)
|
{
|
NNI_ARG_UNUSED(cfg);
|
}
|
|
int
|
nni_tls_config_init(nng_tls_config **cpp, enum nng_tls_mode mode)
|
{
|
NNI_ARG_UNUSED(cpp);
|
NNI_ARG_UNUSED(mode);
|
return (NNG_ENOTSUP);
|
}
|
|
void
|
nni_tls_config_hold(nng_tls_config *cfg)
|
{
|
NNI_ARG_UNUSED(cfg);
|
}
|
|
int
|
nng_tls_config_server_name(nng_tls_config *cfg, const char *name)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(name);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_auth_mode(nng_tls_config *cfg, nng_tls_auth_mode mode)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(mode);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_ca_chain(
|
nng_tls_config *cfg, const char *certs, const char *crl)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(certs);
|
NNI_ARG_UNUSED(crl);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_own_cert(
|
nng_tls_config *cfg, const char *cert, const char *key, const char *pass)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(cert);
|
NNI_ARG_UNUSED(key);
|
NNI_ARG_UNUSED(pass);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_ca_file(nng_tls_config *cfg, const char *path)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(path);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_cert_key_file(
|
nng_tls_config *cfg, const char *path, const char *pass)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(path);
|
NNI_ARG_UNUSED(pass);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_key(nng_tls_config *cfg, const uint8_t *key, size_t size)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(key);
|
NNI_ARG_UNUSED(size);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_pass(nng_tls_config *cfg, const char *pass)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(pass);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nng_tls_config_alloc(nng_tls_config **cfgp, nng_tls_mode mode)
|
{
|
|
NNI_ARG_UNUSED(cfgp);
|
NNI_ARG_UNUSED(mode);
|
return (NNG_ENOTSUP);
|
}
|
|
void
|
nng_tls_config_free(nng_tls_config *cfg)
|
{
|
NNI_ARG_UNUSED(cfg);
|
}
|
|
int
|
nng_tls_config_version(
|
nng_tls_config *cfg, nng_tls_version min_ver, nng_tls_version max_ver)
|
{
|
NNI_ARG_UNUSED(cfg);
|
NNI_ARG_UNUSED(min_ver);
|
NNI_ARG_UNUSED(max_ver);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nni_tls_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
|
{
|
NNI_ARG_UNUSED(dp);
|
NNI_ARG_UNUSED(url);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nni_tls_listener_alloc(nng_stream_listener **lp, const nng_url *url)
|
{
|
NNI_ARG_UNUSED(lp);
|
NNI_ARG_UNUSED(url);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nni_tls_checkopt(const char *nm, const void *buf, size_t sz, nni_type t)
|
{
|
NNI_ARG_UNUSED(nm);
|
NNI_ARG_UNUSED(buf);
|
NNI_ARG_UNUSED(sz);
|
NNI_ARG_UNUSED(t);
|
return (NNG_ENOTSUP);
|
}
|
|
const char *
|
nng_tls_engine_name(void)
|
{
|
return ("none");
|
}
|
|
const char *
|
nng_tls_engine_description(void)
|
{
|
return ("");
|
}
|
|
bool
|
nng_tls_engine_fips_mode(void)
|
{
|
return (false);
|
}
|
|
int
|
nng_tls_engine_register(const nng_tls_engine *engine)
|
{
|
NNI_ARG_UNUSED(engine);
|
return (NNG_ENOTSUP);
|
}
|
|
int
|
nni_tls_sys_init(void)
|
{
|
return (0);
|
}
|
|
void
|
nni_tls_sys_fini(void)
|
{
|
}
|
|
#endif // !NNG_SUPP_TLS
|