about summary refs log tree commit diff
path: root/tls_bio_cb.c
diff options
context:
space:
mode:
Diffstat (limited to 'tls_bio_cb.c')
-rw-r--r--tls_bio_cb.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/tls_bio_cb.c b/tls_bio_cb.c
new file mode 100644
index 0000000..0091808
--- /dev/null
+++ b/tls_bio_cb.c
@@ -0,0 +1,143 @@
+/* $OpenBSD: tls_bio_cb.c,v 1.19 2017/01/12 16:18:39 jsing Exp $ */
+/*
+ * Copyright (c) 2016 Tobias Pape <tobias@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 <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <openssl/bio.h>
+
+#include <tls.h>
+#include "tls_internal.h"
+
+static int bio_cb_write(BIO *bio, const char *buf, int num);
+static int bio_cb_read(BIO *bio, char *buf, int size);
+static int bio_cb_puts(BIO *bio, const char *str);
+static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr);
+
+static BIO_METHOD bio_cb_method = {
+	.type = BIO_TYPE_MEM,
+	.name = "libtls_callbacks",
+	.bwrite = bio_cb_write,
+	.bread = bio_cb_read,
+	.bputs = bio_cb_puts,
+	.ctrl = bio_cb_ctrl,
+};
+
+static BIO_METHOD *
+bio_s_cb(void)
+{
+	return (&bio_cb_method);
+}
+
+static int
+bio_cb_puts(BIO *bio, const char *str)
+{
+	return (bio_cb_write(bio, str, strlen(str)));
+}
+
+static long
+bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+	long ret = 1;
+
+	switch (cmd) {
+	case BIO_CTRL_GET_CLOSE:
+		ret = (long)bio->shutdown;
+		break;
+	case BIO_CTRL_SET_CLOSE:
+		bio->shutdown = (int)num;
+		break;
+	case BIO_CTRL_DUP:
+	case BIO_CTRL_FLUSH:
+		break;
+	case BIO_CTRL_INFO:
+	case BIO_CTRL_GET:
+	case BIO_CTRL_SET:
+	default:
+		ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
+	}
+
+	return (ret);
+}
+
+static int
+bio_cb_write(BIO *bio, const char *buf, int num)
+{
+	struct tls *ctx = bio->ptr;
+	int rv;
+
+	BIO_clear_retry_flags(bio);
+	rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
+	if (rv == TLS_WANT_POLLIN) {
+		BIO_set_retry_read(bio);
+		rv = -1;
+	} else if (rv == TLS_WANT_POLLOUT) {
+		BIO_set_retry_write(bio);
+		rv = -1;
+	}
+	return (rv);
+}
+
+static int
+bio_cb_read(BIO *bio, char *buf, int size)
+{
+	struct tls *ctx = bio->ptr;
+	int rv;
+
+	BIO_clear_retry_flags(bio);
+	rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
+	if (rv == TLS_WANT_POLLIN) {
+		BIO_set_retry_read(bio);
+		rv = -1;
+	} else if (rv == TLS_WANT_POLLOUT) {
+		BIO_set_retry_write(bio);
+		rv = -1;
+	}
+	return (rv);
+}
+
+int
+tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
+    void *cb_arg)
+{
+	int rv = -1;
+	BIO *bio;
+
+	if (read_cb == NULL || write_cb == NULL) {
+		tls_set_errorx(ctx, "no callbacks provided");
+		goto err;
+	}
+
+	ctx->read_cb = read_cb;
+	ctx->write_cb = write_cb;
+	ctx->cb_arg = cb_arg;
+
+	if ((bio = BIO_new(bio_s_cb())) == NULL) {
+		tls_set_errorx(ctx, "failed to create callback i/o");
+		goto err;
+	}
+	bio->ptr = ctx;
+	bio->init = 1;
+
+	SSL_set_bio(ctx->ssl_conn, bio, bio);
+
+	rv = 0;
+
+ err:
+	return (rv);
+}