On Sun, Sep 04, 2016 at 05:26:24AM -0500, Brent Cook wrote:
> On Sun, Sep 04, 2016 at 05:57:54AM -0400, Ted Unangst wrote:
> > Brent Cook wrote:
> > > @@ -246,14 +252,18 @@ An already existing socket can be upgrad
> > > .Fn tls_connect_socket .
> > > Alternatively, a secure connection can be established over a pair of
> > > existing
> > > file descriptors by calling
> > > -.Fn tls_connect_fds .
> > > +.Fn tls_connect_fds . Using
> > > +.Fn tls_connect_cbs , read and write callbacks can be specified to
> > > handle the
> > > +actual data transfer.
> >
> > I think we need just a wee bit more documentation. payload is not the
> > clearest
> > name. It sounds like connection data. I think cookie? Or cbarg? Is it
> > necessary to pass the tls context to the callback? I think that's unusual.
> >
> > read callback should be more like:
> >
> > ssize_t (*read_cb)(void *buf, size_t buflen, void *cbarg);
>
> Agreed, I was also a bit unclear on payload at first (though it grew on
> me over time, so I didn't change it). Here's an update with the
> parameter renamed and better documented.
>
> ok?
Yeah. I'm good with this
IMO get it in so we can tweak it in tree.
ok beck@
and don't forget to bump all the minors of all the things
>
> Index: Makefile
> ===================================================================
> RCS file: /cvs/src/lib/libtls/Makefile,v
> retrieving revision 1.23
> diff -u -p -u -p -r1.23 Makefile
> --- Makefile 30 Mar 2016 06:38:43 -0000 1.23
> +++ Makefile 4 Sep 2016 10:23:42 -0000
> @@ -13,6 +13,7 @@ LDADD+= -L${BSDOBJDIR}/lib/libssl/ssl -l
> HDRS= tls.h
>
> SRCS= tls.c \
> + tls_bio_cb.c \
> tls_client.c \
> tls_config.c \
> tls_conninfo.c \
> Index: shlib_version
> ===================================================================
> RCS file: /cvs/src/lib/libtls/shlib_version,v
> retrieving revision 1.20
> diff -u -p -u -p -r1.20 shlib_version
> --- shlib_version 31 Aug 2016 23:05:30 -0000 1.20
> +++ shlib_version 4 Sep 2016 10:23:42 -0000
> @@ -1,2 +1,2 @@
> major=11
> -minor=3
> +minor=4
> Index: tls.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.c,v
> retrieving revision 1.48
> diff -u -p -u -p -r1.48 tls.c
> --- tls.c 22 Aug 2016 17:12:35 -0000 1.48
> +++ tls.c 4 Sep 2016 10:23:42 -0000
> @@ -424,6 +424,10 @@ tls_reset(struct tls *ctx)
> tls_sni_ctx_free(sni);
> }
> ctx->sni_ctx = NULL;
> +
> + ctx->read_cb = NULL;
> + ctx->write_cb = NULL;
> + ctx->cb_arg = NULL;
> }
>
> int
> Index: tls.h
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.h,v
> retrieving revision 1.35
> diff -u -p -u -p -r1.35 tls.h
> --- tls.h 22 Aug 2016 14:58:26 -0000 1.35
> +++ tls.h 4 Sep 2016 10:23:42 -0000
> @@ -44,6 +44,11 @@ extern "C" {
> struct tls;
> struct tls_config;
>
> +typedef ssize_t (*tls_read_cb)(void *_ctx, void *_buf, size_t _buflen,
> + void *_cb_arg);
> +typedef ssize_t (*tls_write_cb)(void *_ctx, const void *_buf,
> + size_t _buflen, void *_cb_arg);
> +
> int tls_init(void);
>
> const char *tls_config_error(struct tls_config *_config);
> @@ -102,12 +107,16 @@ void tls_free(struct tls *_ctx);
> int tls_accept_fds(struct tls *_ctx, struct tls **_cctx, int _fd_read,
> int _fd_write);
> int tls_accept_socket(struct tls *_ctx, struct tls **_cctx, int _socket);
> +int tls_accept_cbs(struct tls *_ctx, struct tls **_cctx,
> + tls_read_cb _read_cb, tls_write_cb _write_cb, void *_cb_arg);
> int tls_connect(struct tls *_ctx, const char *_host, const char *_port);
> int tls_connect_fds(struct tls *_ctx, int _fd_read, int _fd_write,
> const char *_servername);
> int tls_connect_servername(struct tls *_ctx, const char *_host,
> const char *_port, const char *_servername);
> int tls_connect_socket(struct tls *_ctx, int _s, const char *_servername);
> +int tls_connect_cbs(struct tls *_ctx, tls_read_cb _read_cb,
> + tls_write_cb _write_cb, void *_cb_arg, const char *_servername);
> int tls_handshake(struct tls *_ctx);
> ssize_t tls_read(struct tls *_ctx, void *_buf, size_t _buflen);
> ssize_t tls_write(struct tls *_ctx, const void *_buf, size_t _buflen);
> Index: tls_bio_cb.c
> ===================================================================
> RCS file: tls_bio_cb.c
> diff -N tls_bio_cb.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ tls_bio_cb.c 4 Sep 2016 10:23:42 -0000
> @@ -0,0 +1,224 @@
> +/* $ID$ */
> +/*
> + * Copyright (c) 2016 Tobias Pape <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +
> +#include "tls.h"
> +#include "tls_internal.h"
> +
> +#include <openssl/bio.h>
> +
> +static int write_cb(BIO *b, const char *buf, int num);
> +static int read_cb(BIO *b, char *buf, int size);
> +static int puts_cb(BIO *b, const char *str);
> +static long ctrl_cb(BIO *b, int cmd, long num, void *ptr);
> +static int new_cb(BIO *b);
> +static int free_cb(BIO *data);
> +
> +struct bio_cb_st {
> + int (*write_cb)(BIO *h, const char *buf, int num, void *cb_arg);
> + int (*read_cb)(BIO *h, char *buf, int size, void *cb_arg);
> + void *cb_arg;
> +};
> +
> +static BIO_METHOD cb_method = {
> + .type = BIO_TYPE_MEM,
> + .name = "libtls_callbacks",
> + .bwrite = write_cb,
> + .bread = read_cb,
> + .bputs = puts_cb,
> + .ctrl = ctrl_cb,
> + .create = new_cb,
> + .destroy = free_cb
> +};
> +
> +static BIO_METHOD *
> +bio_s_cb(void)
> +{
> + return (&cb_method);
> +}
> +
> +static int
> +bio_set_write_cb(BIO *bi,
> + int (*write_cb)(BIO *h, const char *buf, int num, void *cb_arg))
> +{
> + struct bio_cb_st *b;
> + b = (struct bio_cb_st *)bi->ptr;
> + b->write_cb = write_cb;
> + return (0);
> +}
> +
> +static int
> +bio_set_read_cb(BIO *bi,
> + int (*read_cb)(BIO *h, char *buf, int size, void *cb_arg))
> +{
> + struct bio_cb_st *b;
> + b = (struct bio_cb_st *)bi->ptr;
> + b->read_cb = read_cb;
> + return (0);
> +}
> +
> +static int
> +bio_set_cb_arg(BIO *bi, void *cb_arg)
> +{
> + struct bio_cb_st *b;
> + b = (struct bio_cb_st *)bi->ptr;
> + b->cb_arg = cb_arg;
> + return (0);
> +}
> +
> +static int
> +new_cb(BIO *bi)
> +{
> + struct bio_cb_st *bcb;
> +
> + bcb = calloc(1, sizeof(struct bio_cb_st));
> + if (bcb == NULL)
> + return (0);
> +
> + bi->shutdown = 1;
> + bi->init = 1;
> + bi->num = -1;
> + bi->ptr = (char *)bcb;
> +
> + return (1);
> +}
> +
> +static int
> +free_cb(BIO *bi)
> +{
> + if (bi == NULL)
> + return (0);
> +
> + if (bi->shutdown) {
> + if ((bi->init) && (bi->ptr != NULL)) {
> + struct bio_cb_st *b;
> + b = (struct bio_cb_st *)bi->ptr;
> + free(b);
> + bi->ptr = NULL;
> + }
> + }
> +
> + return (1);
> +}
> +
> +static int
> +read_cb(BIO *b, char *buf, int size)
> +{
> + struct bio_cb_st *bcb = b->ptr;
> + return (bcb->read_cb(b, buf, size, bcb->cb_arg));
> +}
> +
> +static int
> +write_cb(BIO *b, const char *buf, int num)
> +{
> + struct bio_cb_st *bcb = b->ptr;
> + return (bcb->write_cb(b, buf, num, bcb->cb_arg));
> +}
> +
> +static int
> +puts_cb(BIO *b, const char *str)
> +{
> + int n;
> +
> + n = strlen(str);
> + return (write_cb(b, str, n));
> +}
> +
> +static long
> +ctrl_cb(BIO *b, int cmd, long num, void *ptr)
> +{
> + long ret = 1;
> +
> + switch (cmd) {
> + case BIO_CTRL_GET_CLOSE:
> + ret = (long)b->shutdown;
> + break;
> + case BIO_CTRL_SET_CLOSE:
> + b->shutdown = (int)num;
> + break;
> + case BIO_CTRL_DUP:
> + break;
> + case BIO_CTRL_INFO:
> + case BIO_CTRL_GET:
> + case BIO_CTRL_SET:
> + default:
> + ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
> + }
> +
> + return (ret);
> +}
> +
> +static int
> +tls_bio_write_cb(BIO *h, const char *buf, int num, void *cb_arg)
> +{
> + struct tls *ctx = cb_arg;
> + return (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
> +}
> +
> +static int
> +tls_bio_read_cb(BIO *h, char *buf, int size, void *cb_arg)
> +{
> + struct tls *ctx = cb_arg;
> + return (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
> +}
> +
> +static BIO *
> +tls_get_new_cb_bio(struct tls *ctx)
> +{
> + BIO *bcb;
> + if (ctx->read_cb == NULL || ctx->write_cb == NULL)
> + tls_set_errorx(ctx, "no callbacks registered");
> +
> + bcb = BIO_new(bio_s_cb());
> + if (bcb == NULL) {
> + tls_set_errorx(ctx, "failed to create callback i/o");
> + return (NULL);
> + }
> +
> + bio_set_write_cb(bcb, tls_bio_write_cb);
> + bio_set_read_cb(bcb, tls_bio_read_cb);
> + bio_set_cb_arg(bcb, ctx);
> +
> + return (bcb);
> +}
> +
> +int
> +tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
> + void *cb_arg)
> +{
> + int rv = -1;
> + BIO *bcb;
> + ctx->read_cb = read_cb;
> + ctx->write_cb = write_cb;
> + ctx->cb_arg = cb_arg;
> +
> + bcb = tls_get_new_cb_bio(ctx);
> + if (bcb == NULL) {
> + tls_set_errorx(ctx, "failed to create callback i/o");
> + goto err;
> + }
> +
> + SSL_set_bio(ctx->ssl_conn, bcb, bcb);
> +
> + rv = 0;
> +
> + err:
> + return (rv);
> +}
> Index: tls_client.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_client.c,v
> retrieving revision 1.34
> diff -u -p -u -p -r1.34 tls_client.c
> --- tls_client.c 15 Aug 2016 14:04:23 -0000 1.34
> +++ tls_client.c 4 Sep 2016 10:23:42 -0000
> @@ -158,15 +158,8 @@ tls_connect_servername(struct tls *ctx,
> return (rv);
> }
>
> -int
> -tls_connect_socket(struct tls *ctx, int s, const char *servername)
> -{
> - return tls_connect_fds(ctx, s, s, servername);
> -}
> -
> -int
> -tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
> - const char *servername)
> +static int
> +connect_common(struct tls *ctx, const char *servername)
> {
> union tls_addr addrbuf;
> int rv = -1;
> @@ -176,11 +169,6 @@ tls_connect_fds(struct tls *ctx, int fd_
> goto err;
> }
>
> - if (fd_read < 0 || fd_write < 0) {
> - tls_set_errorx(ctx, "invalid file descriptors");
> - goto err;
> - }
> -
> if (servername != NULL) {
> if ((ctx->servername = strdup(servername)) == NULL) {
> tls_set_errorx(ctx, "out of memory");
> @@ -195,6 +183,7 @@ tls_connect_fds(struct tls *ctx, int fd_
>
> if (tls_configure_ssl(ctx, ctx->ssl_ctx) != 0)
> goto err;
> +
> if (tls_configure_ssl_keypair(ctx, ctx->ssl_ctx,
> ctx->config->keypair, 0) != 0)
> goto err;
> @@ -205,6 +194,7 @@ tls_connect_fds(struct tls *ctx, int fd_
> goto err;
> }
> }
> +
> if (ctx->config->verify_cert &&
> (tls_configure_ssl_verify(ctx, ctx->ssl_ctx,
> SSL_VERIFY_PEER) == -1))
> @@ -214,15 +204,11 @@ tls_connect_fds(struct tls *ctx, int fd_
> tls_set_errorx(ctx, "ssl connection failure");
> goto err;
> }
> +
> if (SSL_set_app_data(ctx->ssl_conn, ctx) != 1) {
> tls_set_errorx(ctx, "ssl application data failure");
> goto err;
> }
> - if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
> - SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
> - tls_set_errorx(ctx, "ssl file descriptor failure");
> - goto err;
> - }
>
> /*
> * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
> @@ -235,6 +221,56 @@ tls_connect_fds(struct tls *ctx, int fd_
> tls_set_errorx(ctx, "server name indication failure");
> goto err;
> }
> + }
> + rv = 0;
> +
> + err:
> + return (rv);
> +}
> +
> +int
> +tls_connect_socket(struct tls *ctx, int s, const char *servername)
> +{
> + return tls_connect_fds(ctx, s, s, servername);
> +}
> +
> +int
> +tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
> + const char *servername)
> +{
> + int rv = -1;
> +
> + if (fd_read < 0 || fd_write < 0) {
> + tls_set_errorx(ctx, "invalid file descriptors");
> + goto err;
> + }
> +
> + if (connect_common(ctx, servername) != 0)
> + goto err;
> +
> + if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
> + SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
> + tls_set_errorx(ctx, "ssl file descriptor failure");
> + goto err;
> + }
> +
> + rv = 0;
> + err:
> + return (rv);
> +}
> +
> +int
> +tls_connect_cbs(struct tls *ctx, tls_read_cb read_cb,
> + tls_write_cb write_cb, void *cb_arg, const char *servername)
> +{
> + int rv = -1;
> +
> + if (connect_common(ctx, servername) != 0)
> + goto err;
> +
> + if (tls_set_cbs(ctx, read_cb, write_cb, cb_arg) != 0) {
> + tls_set_errorx(ctx, "callback registration failure");
> + goto err;
> }
>
> rv = 0;
> Index: tls_init.3
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_init.3,v
> retrieving revision 1.67
> diff -u -p -u -p -r1.67 tls_init.3
> --- tls_init.3 22 Aug 2016 14:55:59 -0000 1.67
> +++ tls_init.3 4 Sep 2016 10:23:43 -0000
> @@ -71,8 +71,10 @@
> .Nm tls_connect_fds ,
> .Nm tls_connect_servername ,
> .Nm tls_connect_socket ,
> +.Nm tls_connect_cbs ,
> .Nm tls_accept_fds ,
> .Nm tls_accept_socket ,
> +.Nm tls_accept_cbs ,
> .Nm tls_handshake ,
> .Nm tls_read ,
> .Nm tls_write ,
> @@ -187,10 +189,14 @@
> .Ft "int"
> .Fn tls_connect_socket "struct tls *ctx" "int s" "const char *servername"
> .Ft "int"
> +.Fn tls_connect_cbs "struct tls *ctx" "ssize_t (*tls_read_cb)(void *ctx,
> void *buf, size_t buflen, void *cb_arg)" "ssize_t (*tls_write_cb)(void *ctx,
> const void *buf, size_t buflen, void *cb_arg)" "void *cb_arg" "const char
> *servername"
> +.Ft "int"
> .Fn tls_accept_fds "struct tls *tls" "struct tls **cctx" "int fd_read" "int
> fd_write"
> .Ft "int"
> .Fn tls_accept_socket "struct tls *tls" "struct tls **cctx" "int socket"
> .Ft "int"
> +.Fn tls_accept_cbs "struct tls *ctx" "struct tls **cctx" "ssize_t
> (*tls_read_cb)(void *ctx, void *buf, size_t buflen, void *cb_arg)" "ssize_t
> (*tls_write_cb)(void *ctx, const void *buf, size_t buflen, void *cb_arg)"
> "void *cb_arg"
> +.Ft "int"
> .Fn tls_handshake "struct tls *ctx"
> .Ft "ssize_t"
> .Fn tls_read "struct tls *ctx" "void *buf" "size_t buflen"
> @@ -247,6 +253,9 @@ An already existing socket can be upgrad
> Alternatively, a secure connection can be established over a pair of existing
> file descriptors by calling
> .Fn tls_connect_fds .
> +Calling
> +.Fn tls_connect_cbs
> +allows specifying read and write callback functions to handle data transfer.
> The specified cb_arg parameter is passed back to the functions, and can
> contain a pointer to any caller-specified data.
> .Pp
> A server can accept a new client connection by calling
> .Fn tls_accept_socket
> @@ -254,6 +263,9 @@ on an already established socket connect
> Alternatively, a new client connection can be accepted over a pair of
> existing
> file descriptors by calling
> .Fn tls_accept_fds .
> +Calling
> +.Fn tls_accept_cbs
> +allows specifying read and write callback functions to handle data transfer.
> The specified cb_arg parameter is passed back to the functions, and can
> contain a pointer to any caller-specified data.
> .Pp
> The TLS handshake can be completed by calling
> .Fn tls_handshake .
> Index: tls_internal.h
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_internal.h,v
> retrieving revision 1.42
> diff -u -p -u -p -r1.42 tls_internal.h
> --- tls_internal.h 22 Aug 2016 17:12:35 -0000 1.42
> +++ tls_internal.h 4 Sep 2016 10:23:43 -0000
> @@ -117,6 +117,10 @@ struct tls {
> X509 *ssl_peer_cert;
>
> struct tls_conninfo *conninfo;
> +
> + tls_read_cb read_cb;
> + tls_write_cb write_cb;
> + void *cb_arg;
> };
>
> struct tls_sni_ctx *tls_sni_ctx_new(void);
> @@ -139,6 +143,9 @@ int tls_handshake_server(struct tls *ctx
> int tls_config_load_file(struct tls_error *error, const char *filetype,
> const char *filename, char **buf, size_t *len);
> int tls_host_port(const char *hostport, char **host, char **port);
> +
> +int tls_set_cbs(struct tls *ctx,
> + tls_read_cb read_cb, tls_write_cb write_cb, void *cb_arg);
>
> int tls_error_set(struct tls_error *error, const char *fmt, ...)
> __attribute__((__format__ (printf, 2, 3)))
> Index: tls_server.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_server.c,v
> retrieving revision 1.25
> diff -u -p -u -p -r1.25 tls_server.c
> --- tls_server.c 22 Aug 2016 14:51:37 -0000 1.25
> +++ tls_server.c 4 Sep 2016 10:23:43 -0000
> @@ -279,14 +279,8 @@ tls_configure_server(struct tls *ctx)
> return (-1);
> }
>
> -int
> -tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket)
> -{
> - return (tls_accept_fds(ctx, cctx, socket, socket));
> -}
> -
> -int
> -tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
> +static struct tls *
> +accept_common(struct tls *ctx)
> {
> struct tls *conn_ctx = NULL;
>
> @@ -304,10 +298,34 @@ tls_accept_fds(struct tls *ctx, struct t
> tls_set_errorx(ctx, "ssl failure");
> goto err;
> }
> +
> if (SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx) != 1) {
> tls_set_errorx(ctx, "ssl application data failure");
> goto err;
> }
> +
> + return conn_ctx;
> +
> + err:
> + tls_free(conn_ctx);
> +
> + return (NULL);
> +}
> +
> +int
> +tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket)
> +{
> + return (tls_accept_fds(ctx, cctx, socket, socket));
> +}
> +
> +int
> +tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
> +{
> + struct tls *conn_ctx;
> +
> + if ((conn_ctx = accept_common(ctx)) == NULL)
> + goto err;
> +
> if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
> SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
> tls_set_errorx(ctx, "ssl file descriptor failure");
> @@ -317,10 +335,32 @@ tls_accept_fds(struct tls *ctx, struct t
> *cctx = conn_ctx;
>
> return (0);
> -
> err:
> tls_free(conn_ctx);
> + *cctx = NULL;
> +
> + return (-1);
> +}
> +
> +int
> +tls_accept_cbs(struct tls *ctx, struct tls **cctx,
> + tls_read_cb read_cb, tls_write_cb write_cb, void *cb_arg)
> +{
> + struct tls *conn_ctx;
> +
> + if ((conn_ctx = accept_common(ctx)) == NULL)
> + goto err;
> +
> + if (tls_set_cbs(ctx, read_cb, write_cb, cb_arg) != 0) {
> + tls_set_errorx(ctx, "callback registration failure");
> + goto err;
> + }
>
> + *cctx = conn_ctx;
> +
> + return (0);
> + err:
> + tls_free(conn_ctx);
> *cctx = NULL;
>
> return (-1);
> Index: tls_verify.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_verify.c,v
> retrieving revision 1.16
> diff -u -p -u -p -r1.16 tls_verify.c
> --- tls_verify.c 2 Aug 2016 07:47:11 -0000 1.16
> +++ tls_verify.c 4 Sep 2016 10:23:43 -0000
> @@ -24,6 +24,7 @@
>
> #include <openssl/x509v3.h>
>
> +#include <tls.h>
> #include "tls_internal.h"
>
> static int tls_match_name(const char *cert_name, const char *name);
>