sync with trunk
This commit is contained in:
commit
7e7b2a8a99
10 changed files with 453 additions and 21 deletions
4
Makefile
4
Makefile
|
@ -6,11 +6,11 @@
|
|||
|
||||
# Master version number
|
||||
VER_MAJOR := 0
|
||||
VER_MINOR := 3
|
||||
VER_MINOR := 4
|
||||
VER_PATCH := 0
|
||||
|
||||
PROJECT := re
|
||||
VERSION := 0.3.0
|
||||
VERSION := 0.4.0
|
||||
|
||||
MK := mk/re.mk
|
||||
|
||||
|
|
|
@ -7,11 +7,26 @@
|
|||
|
||||
struct tls;
|
||||
struct tls_conn;
|
||||
struct tls_sock;
|
||||
struct tcp_conn;
|
||||
struct udp_sock;
|
||||
|
||||
|
||||
int tls_alloc(struct tls **tlsp, const char *keyfile, const char *pwd);
|
||||
/** Defines the TLS method */
|
||||
enum tls_method {
|
||||
TLS_METHOD_SSLV23,
|
||||
TLS_METHOD_DTLSV1,
|
||||
};
|
||||
|
||||
|
||||
int tls_alloc(struct tls **tlsp, enum tls_method method, const char *keyfile,
|
||||
const char *pwd);
|
||||
int tls_add_ca(struct tls *tls, const char *capath);
|
||||
int tls_verify_cert(struct tls_conn *tc, char *cn, size_t cn_size);
|
||||
|
||||
int tls_start_tcp(struct tls_conn **ptc, struct tls *tls,
|
||||
struct tcp_conn *tcp);
|
||||
struct tcp_conn *tcp, int layer);
|
||||
int tls_start_udp(struct tls_sock **tsp, struct tls *tls,
|
||||
struct udp_sock *us, int layer, uint32_t bsize);
|
||||
struct tls_conn *tls_udp_conn(const struct tls_sock *ts,
|
||||
const struct sa *peer);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%define name re
|
||||
%define ver 0.3.0
|
||||
%define rel 2
|
||||
%define ver 0.4.0
|
||||
%define rel 1
|
||||
|
||||
Summary: Generic library for real-time communications with async IO support
|
||||
Name: %name
|
||||
|
|
|
@ -184,7 +184,7 @@ static void tcp_conn_handler(const struct sa *addr, void *arg)
|
|||
|
||||
#ifdef USE_TLS
|
||||
if (bs->transp == BFCP_TRANSP_TLS) {
|
||||
if (tls_start_tcp(&conn->sc, bs->tls, conn->tc))
|
||||
if (tls_start_tcp(&conn->sc, bs->tls, conn->tc, 0))
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
@ -318,7 +318,7 @@ int bfcp_send(struct bfcp_sock *sock, const struct sa *dst, struct mbuf *mb)
|
|||
if (sock->transp == BFCP_TRANSP_TLS) {
|
||||
|
||||
err = tls_start_tcp(&conn->sc, sock->tls,
|
||||
conn->tc);
|
||||
conn->tc, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -510,7 +510,7 @@ static void tcp_connect_handler(const struct sa *paddr, void *arg)
|
|||
|
||||
#ifdef USE_TLS
|
||||
if (transp->tls) {
|
||||
err = tls_start_tcp(&conn->sc, transp->tls, conn->tc);
|
||||
err = tls_start_tcp(&conn->sc, transp->tls, conn->tc, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure,
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = tls_start_tcp(&conn->sc, transp->tls, conn->tc);
|
||||
err = tls_start_tcp(&conn->sc, transp->tls, conn->tc, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -7,4 +7,14 @@
|
|||
ifneq ($(USE_OPENSSL),)
|
||||
SRCS += tls/openssl/tls.c
|
||||
SRCS += tls/openssl/tls_tcp.c
|
||||
|
||||
USE_OPENSSL_DTLS := $(shell [ -f $(SYSROOT)/include/openssl/dtls1.h ] || \
|
||||
[ -f $(SYSROOT)/local/include/openssl/dtls1.h ] || \
|
||||
[ -f $(SYSROOT_ALT)/include/openssl/dtls1.h ] && echo "yes")
|
||||
|
||||
ifneq ($(USE_OPENSSL_DTLS),)
|
||||
CFLAGS += -DUSE_OPENSSL_DTLS=1
|
||||
SRCS += tls/openssl/tls_udp.c
|
||||
endif
|
||||
|
||||
endif
|
||||
|
|
|
@ -49,7 +49,10 @@ static void destructor(void *data)
|
|||
{
|
||||
struct tls *tls = data;
|
||||
|
||||
SSL_CTX_free(tls->ctx);
|
||||
if (tls->ctx)
|
||||
SSL_CTX_free(tls->ctx);
|
||||
|
||||
mem_deref(tls->pass);
|
||||
|
||||
if (--tlsg.tlsc == 0) {
|
||||
DEBUG_INFO("error strings freed\n");
|
||||
|
@ -76,10 +79,11 @@ static int password_cb(char *buf, int size, int rwflag, void *userdata)
|
|||
}
|
||||
|
||||
|
||||
int tls_alloc(struct tls **tlsp, const char *keyfile, const char *pwd)
|
||||
int tls_alloc(struct tls **tlsp, enum tls_method method, const char *keyfile,
|
||||
const char *pwd)
|
||||
{
|
||||
int r, err = ENOMEM;
|
||||
struct tls *tls;
|
||||
int r, err;
|
||||
|
||||
if (!tlsp)
|
||||
return EINVAL;
|
||||
|
@ -103,20 +107,44 @@ int tls_alloc(struct tls **tlsp, const char *keyfile, const char *pwd)
|
|||
SSL_load_error_strings();
|
||||
}
|
||||
|
||||
tls->ctx = SSL_CTX_new(SSLv23_method());
|
||||
if (!tls->ctx)
|
||||
switch (method) {
|
||||
|
||||
case TLS_METHOD_SSLV23:
|
||||
tls->ctx = SSL_CTX_new(SSLv23_method());
|
||||
break;
|
||||
|
||||
#ifdef USE_OPENSSL_DTLS
|
||||
case TLS_METHOD_DTLSV1:
|
||||
tls->ctx = SSL_CTX_new(DTLSv1_method());
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
DEBUG_WARNING("tls method %d not supported\n", method);
|
||||
err = ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tls->ctx) {
|
||||
err = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
|
||||
SSL_CTX_set_verify_depth(tls->ctx, 1);
|
||||
#endif
|
||||
|
||||
if (method == TLS_METHOD_DTLSV1) {
|
||||
SSL_CTX_set_read_ahead(tls->ctx, 1);
|
||||
}
|
||||
|
||||
/* Load our keys and certificates */
|
||||
if (keyfile) {
|
||||
err = EINVAL;
|
||||
|
||||
if (pwd) {
|
||||
tls->pass = pwd;
|
||||
err = str_dup(&tls->pass, pwd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
SSL_CTX_set_default_passwd_cb(tls->ctx, password_cb);
|
||||
SSL_CTX_set_default_passwd_cb_userdata(tls->ctx, tls);
|
||||
}
|
||||
|
@ -125,6 +153,7 @@ int tls_alloc(struct tls **tlsp, const char *keyfile, const char *pwd)
|
|||
if (r <= 0) {
|
||||
DEBUG_WARNING("Can't read certificate file: %s (%d)\n",
|
||||
keyfile, r);
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -133,6 +162,7 @@ int tls_alloc(struct tls **tlsp, const char *keyfile, const char *pwd)
|
|||
if (r <= 0) {
|
||||
DEBUG_WARNING("Can't read key file: %s (%d)\n",
|
||||
keyfile, r);
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
|
||||
struct tls {
|
||||
SSL_CTX *ctx;
|
||||
const char *pass; /* password for private key */
|
||||
char *pass; /* password for private key */
|
||||
};
|
||||
|
|
|
@ -276,10 +276,10 @@ static bool send_handler(int *err, struct mbuf *mb, void *arg)
|
|||
}
|
||||
|
||||
|
||||
int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, struct tcp_conn *tcp)
|
||||
int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, struct tcp_conn *tcp,
|
||||
int layer)
|
||||
{
|
||||
struct tls_conn *tc;
|
||||
const int layer = 0;
|
||||
int err;
|
||||
|
||||
if (!ptc || !tls || !tcp)
|
||||
|
|
377
src/tls/openssl/tls_udp.c
Normal file
377
src/tls/openssl/tls_udp.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/**
|
||||
* @file openssl/tls_udp.c DTLS/UDP backend using OpenSSL
|
||||
*
|
||||
* Copyright (C) 2010 Creytiv.com
|
||||
*/
|
||||
#define OPENSSL_NO_KRB5 1
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <re_types.h>
|
||||
#include <re_fmt.h>
|
||||
#include <re_mem.h>
|
||||
#include <re_mbuf.h>
|
||||
#include <re_list.h>
|
||||
#include <re_hash.h>
|
||||
#include <re_tmr.h>
|
||||
#include <re_sa.h>
|
||||
#include <re_net.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_tls.h>
|
||||
#include "tls.h"
|
||||
|
||||
|
||||
#define DEBUG_MODULE "tls_udp"
|
||||
#define DEBUG_LEVEL 5
|
||||
#include <re_dbg.h>
|
||||
|
||||
|
||||
struct tls_sock {
|
||||
struct udp_helper *uh;
|
||||
struct udp_sock *us;
|
||||
struct hash *ht_conn;
|
||||
struct tls *tls;
|
||||
};
|
||||
|
||||
struct tls_conn {
|
||||
SSL *ssl; /* inheritance */
|
||||
BIO *sbio_out;
|
||||
BIO *sbio_in;
|
||||
struct le he;
|
||||
struct sa peer;
|
||||
struct tmr tmr;
|
||||
struct tls_sock *ts;
|
||||
};
|
||||
|
||||
|
||||
static void check_timer(struct tls_conn *conn);
|
||||
|
||||
|
||||
static int bio_create(BIO *b)
|
||||
{
|
||||
b->init = 1;
|
||||
b->num = 0;
|
||||
b->ptr = NULL;
|
||||
b->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int bio_destroy(BIO *b)
|
||||
{
|
||||
if (!b)
|
||||
return 0;
|
||||
|
||||
b->ptr = NULL;
|
||||
b->init = 0;
|
||||
b->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int bio_write(BIO *b, const char *buf, int len)
|
||||
{
|
||||
struct tls_conn *tc = b->ptr;
|
||||
struct mbuf mb;
|
||||
int err;
|
||||
|
||||
mb.buf = (void *)buf;
|
||||
mb.pos = 0;
|
||||
mb.end = mb.size = len;
|
||||
|
||||
err = udp_send_helper(tc->ts->us, &tc->peer, &mb, tc->ts->uh);
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
(void)b;
|
||||
(void)num;
|
||||
(void)ptr;
|
||||
|
||||
if (cmd == BIO_CTRL_FLUSH) {
|
||||
/* The OpenSSL library needs this */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct bio_method_st bio_udp_send = {
|
||||
BIO_TYPE_SOURCE_SINK,
|
||||
"udp_send",
|
||||
bio_write,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
bio_ctrl,
|
||||
bio_create,
|
||||
bio_destroy,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
static void timeout(void *arg)
|
||||
{
|
||||
struct tls_conn *tc = arg;
|
||||
|
||||
DTLSv1_handle_timeout(tc->ssl);
|
||||
check_timer(tc);
|
||||
}
|
||||
|
||||
|
||||
static void check_timer(struct tls_conn *tc)
|
||||
{
|
||||
struct timeval tv = {0, 0};
|
||||
|
||||
if (DTLSv1_get_timeout(tc->ssl, &tv)) {
|
||||
tmr_start(&tc->tmr, tv.tv_sec * 1000 + tv.tv_usec / 1000,
|
||||
timeout, tc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void destructor(void *arg)
|
||||
{
|
||||
struct tls_sock *ts = arg;
|
||||
|
||||
hash_flush(ts->ht_conn);
|
||||
mem_deref(ts->ht_conn);
|
||||
mem_deref(ts->uh);
|
||||
mem_deref(ts->us);
|
||||
mem_deref(ts->tls);
|
||||
}
|
||||
|
||||
|
||||
static void conn_destructor(void *arg)
|
||||
{
|
||||
struct tls_conn *tc = arg;
|
||||
|
||||
hash_unlink(&tc->he);
|
||||
tmr_cancel(&tc->tmr);
|
||||
|
||||
if (tc->ssl) {
|
||||
(void)SSL_shutdown(tc->ssl);
|
||||
SSL_free(tc->ssl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool hash_cmp_handler(struct le *le, void *arg)
|
||||
{
|
||||
const struct tls_conn *tc = le->data;
|
||||
|
||||
return sa_cmp(&tc->peer, arg, SA_ALL);
|
||||
}
|
||||
|
||||
|
||||
static struct tls_conn *conn_alloc(struct tls_sock *ts, const struct sa *peer)
|
||||
{
|
||||
struct tls_conn *tc;
|
||||
|
||||
tc = mem_zalloc(sizeof(*tc), conn_destructor);
|
||||
if (!tc)
|
||||
return NULL;
|
||||
|
||||
tc->ssl = SSL_new(ts->tls->ctx);
|
||||
if (!tc->ssl)
|
||||
goto error;
|
||||
|
||||
tc->sbio_in = BIO_new(BIO_s_mem());
|
||||
if (!tc->sbio_in)
|
||||
goto error;
|
||||
|
||||
tc->sbio_out = BIO_new(&bio_udp_send);
|
||||
if (!tc->sbio_out) {
|
||||
BIO_free(tc->sbio_in);
|
||||
goto error;
|
||||
}
|
||||
tc->sbio_out->ptr = tc;
|
||||
|
||||
SSL_set_bio(tc->ssl, tc->sbio_in, tc->sbio_out);
|
||||
|
||||
tmr_init(&tc->tmr);
|
||||
|
||||
tc->peer = *peer;
|
||||
tc->ts = ts;
|
||||
|
||||
hash_append(ts->ht_conn, sa_hash(peer, SA_ALL), &tc->he, tc);
|
||||
|
||||
return tc;
|
||||
|
||||
error:
|
||||
return mem_deref(tc);
|
||||
}
|
||||
|
||||
|
||||
static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct tls_sock *ts = arg;
|
||||
struct tls_conn *tc;
|
||||
int r;
|
||||
|
||||
tc = tls_udp_conn(ts, dst);
|
||||
if (!tc) {
|
||||
|
||||
/* No connection found, assuming Client role */
|
||||
|
||||
tc = conn_alloc(ts, dst);
|
||||
if (!tc) {
|
||||
*err = ENOMEM;
|
||||
return true;
|
||||
}
|
||||
|
||||
SSL_set_connect_state(tc->ssl);
|
||||
|
||||
check_timer(tc);
|
||||
}
|
||||
|
||||
r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb));
|
||||
if (r < 0) {
|
||||
|
||||
switch (SSL_get_error(tc->ssl, r)) {
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARNING("SSL_write: %d\n",
|
||||
SSL_get_error(tc->ssl, r));
|
||||
*err = EPROTO;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct tls_sock *ts = arg;
|
||||
struct tls_conn *tc;
|
||||
int r;
|
||||
|
||||
tc = tls_udp_conn(ts, src);
|
||||
if (!tc) {
|
||||
|
||||
/* No connection found, assuming Server role */
|
||||
|
||||
tc = conn_alloc(ts, src);
|
||||
if (!tc)
|
||||
return true;
|
||||
|
||||
SSL_set_verify(tc->ssl, 0, 0);
|
||||
SSL_set_accept_state(tc->ssl);
|
||||
}
|
||||
|
||||
/* feed SSL data to the BIO */
|
||||
r = BIO_write(tc->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb));
|
||||
if (r <= 0)
|
||||
return true;
|
||||
|
||||
check_timer(tc);
|
||||
|
||||
mbuf_set_pos(mb, 0);
|
||||
|
||||
for (;;) {
|
||||
int n;
|
||||
|
||||
if (mbuf_get_space(mb) < 4096) {
|
||||
if (mbuf_resize(mb, mb->size + 8192))
|
||||
return true;
|
||||
}
|
||||
|
||||
n = SSL_read(tc->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb));
|
||||
if (n < 0) {
|
||||
const int ssl_err = SSL_get_error(tc->ssl, n);
|
||||
|
||||
switch (ssl_err) {
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (n == 0)
|
||||
break;
|
||||
|
||||
mb->pos += n;
|
||||
}
|
||||
|
||||
if (!mb->pos)
|
||||
return true;
|
||||
|
||||
mbuf_set_end(mb, mb->pos);
|
||||
mbuf_set_pos(mb, 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start TLS on a UDP socket (aka DTLS). The UDP socket can act as a
|
||||
* client or a server, and multiple DTLS connections can be established to
|
||||
* multiple peers, all from the same UDP socket.
|
||||
*
|
||||
* @param tsp Pointer to allocated TLS socket
|
||||
* @param tls TLS context
|
||||
* @param us UDP socket
|
||||
* @param layer Protocol stack layer
|
||||
* @param bsize Bucket size for hash table (0 for default)
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int tls_start_udp(struct tls_sock **tsp, struct tls *tls, struct udp_sock *us,
|
||||
int layer, uint32_t bsize)
|
||||
{
|
||||
struct tls_sock *ts;
|
||||
int err;
|
||||
|
||||
if (!tsp || !tls || !us)
|
||||
return EINVAL;
|
||||
|
||||
ts = mem_zalloc(sizeof(*ts), destructor);
|
||||
if (!ts)
|
||||
return ENOMEM;
|
||||
|
||||
err = hash_alloc(&ts->ht_conn, bsize ? bsize : 4);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = udp_register_helper(&ts->uh, us, layer, send_handler,
|
||||
recv_handler, ts);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ts->us = mem_ref(us);
|
||||
ts->tls = mem_ref(tls);
|
||||
|
||||
out:
|
||||
if (err)
|
||||
mem_deref(ts);
|
||||
else
|
||||
*tsp = ts;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
struct tls_conn *tls_udp_conn(const struct tls_sock *ts, const struct sa *peer)
|
||||
{
|
||||
if (!ts)
|
||||
return NULL;
|
||||
|
||||
return list_ledata(hash_lookup(ts->ht_conn, sa_hash(peer, SA_ALL),
|
||||
hash_cmp_handler, (void *)peer));
|
||||
}
|
Loading…
Add table
Reference in a new issue