xref: /openbsd-src/lib/libtls/tls_bio_cb.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: tls_bio_cb.c,v 1.5 2016/09/14 11:30:41 bcook 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  */
17 
18 #include <fcntl.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 
22 #include <openssl/bio.h>
23 
24 #include <tls.h>
25 #include "tls_internal.h"
26 
27 static int write_cb(BIO *b, const char *buf, int num);
28 static int read_cb(BIO *b, char *buf, int size);
29 static int puts_cb(BIO *b, const char *str);
30 static long ctrl_cb(BIO *b, int cmd, long num, void *ptr);
31 static int new_cb(BIO *b);
32 static int free_cb(BIO *data);
33 
34 struct bio_cb_st {
35 	int (*write_cb)(BIO *h, const char *buf, int num, void *cb_arg);
36 	int (*read_cb)(BIO *h, char *buf, int size, void *cb_arg);
37 	void *cb_arg;
38 };
39 
40 static BIO_METHOD cb_method = {
41 	.type = BIO_TYPE_MEM,
42 	.name = "libtls_callbacks",
43 	.bwrite = write_cb,
44 	.bread = read_cb,
45 	.bputs = puts_cb,
46 	.ctrl = ctrl_cb,
47 	.create = new_cb,
48 	.destroy = free_cb
49 };
50 
51 static BIO_METHOD *
52 bio_s_cb(void)
53 {
54 	return (&cb_method);
55 }
56 
57 static int
58 bio_set_write_cb(BIO *bi,
59     int (*write_cb)(BIO *h, const char *buf, int num, void *cb_arg))
60 {
61 	struct bio_cb_st *b;
62 	b = (struct bio_cb_st *)bi->ptr;
63 	b->write_cb = write_cb;
64 	return (0);
65 }
66 
67 static int
68 bio_set_read_cb(BIO *bi,
69     int (*read_cb)(BIO *h, char *buf, int size, void *cb_arg))
70 {
71 	struct bio_cb_st *b;
72 	b = (struct bio_cb_st *)bi->ptr;
73 	b->read_cb = read_cb;
74 	return (0);
75 }
76 
77 static int
78 bio_set_cb_arg(BIO *bi, void *cb_arg)
79 {
80 	struct bio_cb_st *b;
81 	b = (struct bio_cb_st *)bi->ptr;
82 	b->cb_arg = cb_arg;
83 	return (0);
84 }
85 
86 static int
87 new_cb(BIO *bi)
88 {
89 	struct bio_cb_st *bcb;
90 
91 	bcb = calloc(1, sizeof(struct bio_cb_st));
92 	if (bcb == NULL)
93 		return (0);
94 
95 	bi->shutdown = 1;
96 	bi->init = 1;
97 	bi->num = -1;
98 	bi->ptr = (char *)bcb;
99 
100 	return (1);
101 }
102 
103 static int
104 free_cb(BIO *bi)
105 {
106 	if (bi == NULL)
107 		return (0);
108 
109 	if (bi->shutdown) {
110 		if ((bi->init) && (bi->ptr != NULL)) {
111 			struct bio_cb_st *b;
112 			b = (struct bio_cb_st *)bi->ptr;
113 			free(b);
114 			bi->ptr = NULL;
115 		}
116 	}
117 
118 	return (1);
119 }
120 
121 static int
122 read_cb(BIO *b, char *buf, int size)
123 {
124 	struct bio_cb_st *bcb = b->ptr;
125 	return (bcb->read_cb(b, buf, size, bcb->cb_arg));
126 }
127 
128 static int
129 write_cb(BIO *b, const char *buf, int num)
130 {
131 	struct bio_cb_st *bcb = b->ptr;
132 	return (bcb->write_cb(b, buf, num, bcb->cb_arg));
133 }
134 
135 static int
136 puts_cb(BIO *b, const char *str)
137 {
138 	int n;
139 
140 	n = strlen(str);
141 	return (write_cb(b, str, n));
142 }
143 
144 static long
145 ctrl_cb(BIO *b, int cmd, long num, void *ptr)
146 {
147 	long ret = 1;
148 
149 	switch (cmd) {
150 	case BIO_CTRL_GET_CLOSE:
151 		ret = (long)b->shutdown;
152 		break;
153 	case BIO_CTRL_SET_CLOSE:
154 		b->shutdown = (int)num;
155 		break;
156 	case BIO_CTRL_DUP:
157 	case BIO_CTRL_FLUSH:
158 		break;
159 	case BIO_CTRL_INFO:
160 	case BIO_CTRL_GET:
161 	case BIO_CTRL_SET:
162 	default:
163 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
164 	}
165 
166 	return (ret);
167 }
168 
169 static int
170 tls_bio_write_cb(BIO *h, const char *buf, int num, void *cb_arg)
171 {
172 	struct tls *ctx = cb_arg;
173 	BIO_clear_retry_flags(h);
174 	int rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
175 	if (rv == TLS_WANT_POLLIN) {
176 		BIO_set_retry_read(h);
177 		rv = -1;
178 	} else if (rv == TLS_WANT_POLLOUT) {
179 		BIO_set_retry_write(h);
180 		rv = -1;
181 	}
182 	return (rv);
183 }
184 
185 static int
186 tls_bio_read_cb(BIO *h, char *buf, int size, void *cb_arg)
187 {
188 	struct tls *ctx = cb_arg;
189 	BIO_clear_retry_flags(h);
190 	int rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
191 	if (rv == TLS_WANT_POLLIN) {
192 		BIO_set_retry_read(h);
193 		rv = -1;
194 	} else if (rv == TLS_WANT_POLLOUT) {
195 		BIO_set_retry_write(h);
196 		rv = -1;
197 	}
198 	return (rv);
199 }
200 
201 static BIO *
202 tls_get_new_cb_bio(struct tls *ctx)
203 {
204 	BIO *bcb;
205 	if (ctx->read_cb == NULL || ctx->write_cb == NULL)
206 		tls_set_errorx(ctx, "no callbacks registered");
207 
208 	bcb = BIO_new(bio_s_cb());
209 	if (bcb == NULL) {
210 		tls_set_errorx(ctx, "failed to create callback i/o");
211 		return (NULL);
212 	}
213 
214 	bio_set_write_cb(bcb, tls_bio_write_cb);
215 	bio_set_read_cb(bcb, tls_bio_read_cb);
216 	bio_set_cb_arg(bcb, ctx);
217 
218 	return (bcb);
219 }
220 
221 int
222 tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
223     void *cb_arg)
224 {
225 	int rv = -1;
226 	BIO *bcb;
227 	ctx->read_cb = read_cb;
228 	ctx->write_cb = write_cb;
229 	ctx->cb_arg = cb_arg;
230 
231 	bcb = tls_get_new_cb_bio(ctx);
232 	if (bcb == NULL) {
233 		tls_set_errorx(ctx, "failed to create callback i/o");
234 		goto err;
235 	}
236 
237 	SSL_set_bio(ctx->ssl_conn, bcb, bcb);
238 
239 	rv = 0;
240 
241  err:
242 	return (rv);
243 }
244