1 /* $OpenBSD: evbuffer_tls.c,v 1.14 2024/11/07 10:12:18 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 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 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 tls_close(ctx); 115 what |= EVBUFFER_EOF; 116 break; 117 } 118 if (res <= 0) 119 goto error; 120 121 event_del(&bufev->ev_write); 122 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 123 if (bufev->enabled & EV_READ) 124 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 125 if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE) 126 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 127 128 /* See if this callbacks meets the water marks */ 129 len = EVBUFFER_LENGTH(bufev->input); 130 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) 131 return; 132 if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { 133 struct evbuffer *buf = bufev->input; 134 event_del(&bufev->ev_read); 135 136 /* Now schedule a callback for us when the buffer changes */ 137 evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); 138 } 139 140 /* Invoke the user callback - must always be called last */ 141 if (bufev->readcb != NULL) 142 (*bufev->readcb)(bufev, bufev->cbarg); 143 return; 144 145 error: 146 (*bufev->errorcb)(bufev, what, bufev->cbarg); 147 } 148 149 static void 150 buffertls_writecb(int fd, short event, void *arg) 151 { 152 struct buffertls *buftls = arg; 153 struct bufferevent *bufev = buftls->bt_bufev; 154 struct tls *ctx = buftls->bt_ctx; 155 int res = 0; 156 short what = EVBUFFER_WRITE; 157 158 if (event == EV_TIMEOUT) { 159 what |= EVBUFFER_TIMEOUT; 160 goto error; 161 } 162 163 if (EVBUFFER_LENGTH(bufev->output) != 0) { 164 res = evtls_write(bufev->output, fd, ctx); 165 switch (res) { 166 case TLS_WANT_POLLIN: 167 event_del(&bufev->ev_read); 168 event_set(&bufev->ev_read, fd, EV_READ, 169 buffertls_writecb, buftls); 170 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 171 return; 172 case TLS_WANT_POLLOUT: 173 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 174 return; 175 case -1: 176 what |= EVBUFFER_ERROR; 177 break; 178 case 0: 179 what |= EVBUFFER_EOF; 180 break; 181 } 182 if (res <= 0) 183 goto error; 184 } 185 186 event_del(&bufev->ev_read); 187 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 188 if (bufev->enabled & EV_READ) 189 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 190 if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE) 191 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 192 193 /* 194 * Invoke the user callback if our buffer is drained or below the 195 * low watermark. 196 */ 197 if (bufev->writecb != NULL && 198 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) 199 (*bufev->writecb)(bufev, bufev->cbarg); 200 201 return; 202 203 error: 204 (*bufev->errorcb)(bufev, what, bufev->cbarg); 205 } 206 207 static void 208 buffertls_handshakecb(int fd, short event, void *arg) 209 { 210 struct buffertls *buftls = arg; 211 struct bufferevent *bufev = buftls->bt_bufev; 212 struct tls *ctx = buftls->bt_ctx; 213 int res = 0; 214 short what = EVBUFFER_HANDSHAKE; 215 216 if (event == EV_TIMEOUT) { 217 what |= EVBUFFER_TIMEOUT; 218 goto error; 219 } 220 221 res = tls_handshake(ctx); 222 switch (res) { 223 case TLS_WANT_POLLIN: 224 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 225 return; 226 case TLS_WANT_POLLOUT: 227 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 228 return; 229 case -1: 230 what |= EVBUFFER_ERROR; 231 break; 232 } 233 if (res == -1) 234 goto error; 235 236 /* Handshake was successful, change to read and write callback. */ 237 event_del(&bufev->ev_read); 238 event_del(&bufev->ev_write); 239 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 240 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 241 if (bufev->enabled & EV_READ) 242 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 243 if (bufev->enabled & EV_WRITE) 244 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 245 246 return; 247 248 error: 249 (*bufev->errorcb)(bufev, what, bufev->cbarg); 250 } 251 252 void 253 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev, 254 struct tls *ctx, int fd) 255 { 256 bufferevent_setfd(bufev, fd); 257 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 258 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 259 buftls->bt_bufev = bufev; 260 buftls->bt_ctx = ctx; 261 } 262 263 void 264 buffertls_accept(struct buffertls *buftls, int fd) 265 { 266 struct bufferevent *bufev = buftls->bt_bufev; 267 268 event_del(&bufev->ev_read); 269 event_del(&bufev->ev_write); 270 event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls); 271 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb, 272 buftls); 273 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 274 } 275 276 void 277 buffertls_connect(struct buffertls *buftls, int fd) 278 { 279 struct bufferevent *bufev = buftls->bt_bufev; 280 281 event_del(&bufev->ev_read); 282 event_del(&bufev->ev_write); 283 event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls); 284 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb, 285 buftls); 286 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 287 } 288 289 /* 290 * Reads data from a file descriptor into a buffer. 291 */ 292 293 #define EVBUFFER_MAX_READ 16384 294 295 int 296 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx) 297 { 298 u_char *p; 299 size_t oldoff = buf->off; 300 int n = EVBUFFER_MAX_READ; 301 302 if (howmuch < 0 || howmuch > n) 303 howmuch = n; 304 305 /* If we don't have FIONREAD, we might waste some space here */ 306 if (evbuffer_expand(buf, howmuch) == -1) 307 return (-1); 308 309 /* We can append new data at this point */ 310 p = buf->buffer + buf->off; 311 312 n = tls_read(ctx, p, howmuch); 313 if (n <= 0) 314 return (n); 315 316 buf->off += n; 317 318 /* Tell someone about changes in this buffer */ 319 if (buf->off != oldoff && buf->cb != NULL) 320 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 321 322 return (n); 323 } 324 325 int 326 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx) 327 { 328 int n; 329 330 n = tls_write(ctx, buffer->buffer, buffer->off); 331 if (n <= 0) 332 return (n); 333 evbuffer_drain(buffer, n); 334 335 return (n); 336 } 337