1 /* $OpenBSD: evbuffer_tls.c,v 1.3 2017/07/04 15:52:26 bluhm Exp $ */
2
3 /*
4 * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
5 * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@openbsd.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/ioctl.h>
34
35 #include <errno.h>
36 #include <event.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <tls.h>
41
42 #include "evbuffer_tls.h"
43
44 /* prototypes */
45
46 void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
47 static void buffertls_readcb(int, short, void *);
48 static void buffertls_writecb(int, short, void *);
49 static void buffertls_handshakecb(int, short, void *);
50 int evtls_read(struct evbuffer *, int, int, struct tls *);
51 int evtls_write(struct evbuffer *, int, struct tls *);
52
53 static int
bufferevent_add(struct event * ev,int timeout)54 bufferevent_add(struct event *ev, int timeout)
55 {
56 struct timeval tv, *ptv = NULL;
57
58 if (timeout) {
59 timerclear(&tv);
60 tv.tv_sec = timeout;
61 ptv = &tv;
62 }
63
64 return (event_add(ev, ptv));
65 }
66
67 static void
buffertls_readcb(int fd,short event,void * arg)68 buffertls_readcb(int fd, short event, void *arg)
69 {
70 struct buffertls *buftls = arg;
71 struct bufferevent *bufev = buftls->bt_bufev;
72 struct tls *ctx = buftls->bt_ctx;
73 int res = 0;
74 short what = EVBUFFER_READ;
75 size_t len;
76 int howmuch = -1;
77
78 if (event == EV_TIMEOUT) {
79 what |= EVBUFFER_TIMEOUT;
80 goto error;
81 }
82
83 /*
84 * If we have a high watermark configured then we don't want to
85 * read more data than would make us reach the watermark.
86 */
87 if (bufev->wm_read.high != 0) {
88 howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
89 /* we might have lowered the watermark, stop reading */
90 if (howmuch <= 0) {
91 struct evbuffer *buf = bufev->input;
92 event_del(&bufev->ev_read);
93 evbuffer_setcb(buf,
94 bufferevent_read_pressure_cb, bufev);
95 return;
96 }
97 }
98
99 res = evtls_read(bufev->input, fd, howmuch, ctx);
100 switch (res) {
101 case TLS_WANT_POLLIN:
102 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
103 return;
104 case TLS_WANT_POLLOUT:
105 event_del(&bufev->ev_write);
106 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_readcb,
107 buftls);
108 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
109 return;
110 case -1:
111 what |= EVBUFFER_ERROR;
112 break;
113 case 0:
114 what |= EVBUFFER_EOF;
115 break;
116 }
117 if (res <= 0)
118 goto error;
119
120 event_del(&bufev->ev_write);
121 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
122 if (bufev->enabled & EV_READ)
123 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
124 if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
125 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
126
127 /* See if this callbacks meets the water marks */
128 len = EVBUFFER_LENGTH(bufev->input);
129 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
130 return;
131 if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
132 struct evbuffer *buf = bufev->input;
133 event_del(&bufev->ev_read);
134
135 /* Now schedule a callback for us when the buffer changes */
136 evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
137 }
138
139 /* Invoke the user callback - must always be called last */
140 if (bufev->readcb != NULL)
141 (*bufev->readcb)(bufev, bufev->cbarg);
142 return;
143
144 error:
145 (*bufev->errorcb)(bufev, what, bufev->cbarg);
146 }
147
148 static void
buffertls_writecb(int fd,short event,void * arg)149 buffertls_writecb(int fd, short event, void *arg)
150 {
151 struct buffertls *buftls = arg;
152 struct bufferevent *bufev = buftls->bt_bufev;
153 struct tls *ctx = buftls->bt_ctx;
154 int res = 0;
155 short what = EVBUFFER_WRITE;
156
157 if (event == EV_TIMEOUT) {
158 what |= EVBUFFER_TIMEOUT;
159 goto error;
160 }
161
162 if (EVBUFFER_LENGTH(bufev->output) != 0) {
163 res = evtls_write(bufev->output, fd, ctx);
164 switch (res) {
165 case TLS_WANT_POLLIN:
166 event_del(&bufev->ev_read);
167 event_set(&bufev->ev_read, fd, EV_READ,
168 buffertls_writecb, buftls);
169 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
170 return;
171 case TLS_WANT_POLLOUT:
172 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
173 return;
174 case -1:
175 what |= EVBUFFER_ERROR;
176 break;
177 case 0:
178 what |= EVBUFFER_EOF;
179 break;
180 }
181 if (res <= 0)
182 goto error;
183 }
184
185 event_del(&bufev->ev_read);
186 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
187 if (bufev->enabled & EV_READ)
188 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
189 if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
190 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
191
192 /*
193 * Invoke the user callback if our buffer is drained or below the
194 * low watermark.
195 */
196 if (bufev->writecb != NULL &&
197 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
198 (*bufev->writecb)(bufev, bufev->cbarg);
199
200 return;
201
202 error:
203 (*bufev->errorcb)(bufev, what, bufev->cbarg);
204 }
205
206 static void
buffertls_handshakecb(int fd,short event,void * arg)207 buffertls_handshakecb(int fd, short event, void *arg)
208 {
209 struct buffertls *buftls = arg;
210 struct bufferevent *bufev = buftls->bt_bufev;
211 struct tls *ctx = buftls->bt_ctx;
212 int res = 0;
213 short what = EVBUFFER_HANDSHAKE;
214
215 if (event == EV_TIMEOUT) {
216 what |= EVBUFFER_TIMEOUT;
217 goto error;
218 }
219
220 res = tls_handshake(ctx);
221 switch (res) {
222 case TLS_WANT_POLLIN:
223 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
224 return;
225 case TLS_WANT_POLLOUT:
226 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
227 return;
228 case -1:
229 what |= EVBUFFER_ERROR;
230 break;
231 }
232 if (res < 0)
233 goto error;
234
235 /* Handshake was successful, change to read and write callback. */
236 event_del(&bufev->ev_read);
237 event_del(&bufev->ev_write);
238 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
239 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
240 if (bufev->enabled & EV_READ)
241 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
242 if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
243 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
244
245 return;
246
247 error:
248 (*bufev->errorcb)(bufev, what, bufev->cbarg);
249 }
250
251 void
buffertls_set(struct buffertls * buftls,struct bufferevent * bufev,struct tls * ctx,int fd)252 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev,
253 struct tls *ctx, int fd)
254 {
255 bufferevent_setfd(bufev, fd);
256 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
257 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
258 buftls->bt_bufev = bufev;
259 buftls->bt_ctx = ctx;
260 }
261
262 void
buffertls_accept(struct buffertls * buftls,int fd)263 buffertls_accept(struct buffertls *buftls, int fd)
264 {
265 struct bufferevent *bufev = buftls->bt_bufev;
266
267 event_del(&bufev->ev_read);
268 event_del(&bufev->ev_write);
269 event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls);
270 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb,
271 buftls);
272 bufferevent_add(&bufev->ev_read, bufev->timeout_read);
273 }
274
275 void
buffertls_connect(struct buffertls * buftls,int fd)276 buffertls_connect(struct buffertls *buftls, int fd)
277 {
278 struct bufferevent *bufev = buftls->bt_bufev;
279
280 event_del(&bufev->ev_read);
281 event_del(&bufev->ev_write);
282 event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls);
283 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb,
284 buftls);
285 bufferevent_add(&bufev->ev_write, bufev->timeout_write);
286 }
287
288 /*
289 * Reads data from a file descriptor into a buffer.
290 */
291
292 #define EVBUFFER_MAX_READ 16384
293
294 int
evtls_read(struct evbuffer * buf,int fd,int howmuch,struct tls * ctx)295 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx)
296 {
297 u_char *p;
298 size_t oldoff = buf->off;
299 int n = EVBUFFER_MAX_READ;
300
301 if (howmuch < 0 || howmuch > n)
302 howmuch = n;
303
304 /* If we don't have FIONREAD, we might waste some space here */
305 if (evbuffer_expand(buf, howmuch) == -1)
306 return (-1);
307
308 /* We can append new data at this point */
309 p = buf->buffer + buf->off;
310
311 n = tls_read(ctx, p, howmuch);
312 if (n <= 0)
313 return (n);
314
315 buf->off += n;
316
317 /* Tell someone about changes in this buffer */
318 if (buf->off != oldoff && buf->cb != NULL)
319 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
320
321 return (n);
322 }
323
324 int
evtls_write(struct evbuffer * buffer,int fd,struct tls * ctx)325 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx)
326 {
327 int n;
328
329 n = tls_write(ctx, buffer->buffer, buffer->off);
330 if (n <= 0)
331 return (n);
332 evbuffer_drain(buffer, n);
333
334 return (n);
335 }
336