Blob


1 /* $OpenBSD: tls_bio_cb.c,v 1.21 2023/05/14 07:26:25 op Exp $ */
2 /*
3 * Copyright (c) 2016 Tobias Pape <tobias@netshed.de>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #include "config.h"
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include <openssl/bio.h>
27 #include <tls.h>
28 #include "tls_internal.h"
30 static int bio_cb_write(BIO *bio, const char *buf, int num);
31 static int bio_cb_read(BIO *bio, char *buf, int size);
32 static int bio_cb_puts(BIO *bio, const char *str);
33 static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr);
35 static BIO_METHOD *bio_cb_method;
37 static void
38 bio_cb_method_init(void)
39 {
40 BIO_METHOD *bio_method;
42 if (bio_cb_method != NULL)
43 return;
45 bio_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks");
46 if (bio_method == NULL)
47 return;
49 BIO_meth_set_write(bio_method, bio_cb_write);
50 BIO_meth_set_read(bio_method, bio_cb_read);
51 BIO_meth_set_puts(bio_method, bio_cb_puts);
52 BIO_meth_set_ctrl(bio_method, bio_cb_ctrl);
54 bio_cb_method = bio_method;
55 }
57 static BIO_METHOD *
58 bio_s_cb(void)
59 {
60 if (bio_cb_method != NULL)
61 return (bio_cb_method);
63 bio_cb_method_init();
65 return (bio_cb_method);
66 }
68 static int
69 bio_cb_puts(BIO *bio, const char *str)
70 {
71 return (bio_cb_write(bio, str, strlen(str)));
72 }
74 static long
75 bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr)
76 {
77 long ret = 1;
79 switch (cmd) {
80 case BIO_CTRL_GET_CLOSE:
81 ret = (long)BIO_get_shutdown(bio);
82 break;
83 case BIO_CTRL_SET_CLOSE:
84 BIO_set_shutdown(bio, (int)num);
85 break;
86 case BIO_CTRL_DUP:
87 case BIO_CTRL_FLUSH:
88 break;
89 case BIO_CTRL_INFO:
90 case BIO_CTRL_GET:
91 case BIO_CTRL_SET:
92 default:
93 ret = BIO_ctrl(BIO_next(bio), cmd, num, ptr);
94 }
96 return (ret);
97 }
99 static int
100 bio_cb_write(BIO *bio, const char *buf, int num)
102 struct tls *ctx = BIO_get_data(bio);
103 int rv;
105 BIO_clear_retry_flags(bio);
106 rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
107 if (rv == TLS_WANT_POLLIN) {
108 BIO_set_retry_read(bio);
109 rv = -1;
110 } else if (rv == TLS_WANT_POLLOUT) {
111 BIO_set_retry_write(bio);
112 rv = -1;
114 return (rv);
117 static int
118 bio_cb_read(BIO *bio, char *buf, int size)
120 struct tls *ctx = BIO_get_data(bio);
121 int rv;
123 BIO_clear_retry_flags(bio);
124 rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
125 if (rv == TLS_WANT_POLLIN) {
126 BIO_set_retry_read(bio);
127 rv = -1;
128 } else if (rv == TLS_WANT_POLLOUT) {
129 BIO_set_retry_write(bio);
130 rv = -1;
132 return (rv);
135 int
136 tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
137 void *cb_arg)
139 const BIO_METHOD *bio_cb;
140 BIO *bio;
141 int rv = -1;
143 if (read_cb == NULL || write_cb == NULL) {
144 tls_set_errorx(ctx, "no callbacks provided");
145 goto err;
148 ctx->read_cb = read_cb;
149 ctx->write_cb = write_cb;
150 ctx->cb_arg = cb_arg;
152 if ((bio_cb = bio_s_cb()) == NULL) {
153 tls_set_errorx(ctx, "failed to create callback method");
154 goto err;
156 if ((bio = BIO_new(bio_cb)) == NULL) {
157 tls_set_errorx(ctx, "failed to create callback i/o");
158 goto err;
160 BIO_set_data(bio, ctx);
161 BIO_set_init(bio, 1);
163 SSL_set_bio(ctx->ssl_conn, bio, bio);
165 rv = 0;
167 err:
168 return (rv);