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