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?

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 <tob...@netshed.de>
+ *
+ * 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);

Reply via email to