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