1 /* $OpenBSD: tls_bio_cb.c,v 1.19 2017/01/12 16:18:39 jsing 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 bio_cb_write(BIO *bio, const char *buf, int num); 28 static int bio_cb_read(BIO *bio, char *buf, int size); 29 static int bio_cb_puts(BIO *bio, const char *str); 30 static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr); 31 32 static BIO_METHOD bio_cb_method = { 33 .type = BIO_TYPE_MEM, 34 .name = "libtls_callbacks", 35 .bwrite = bio_cb_write, 36 .bread = bio_cb_read, 37 .bputs = bio_cb_puts, 38 .ctrl = bio_cb_ctrl, 39 }; 40 41 static BIO_METHOD * 42 bio_s_cb(void) 43 { 44 return (&bio_cb_method); 45 } 46 47 static int 48 bio_cb_puts(BIO *bio, const char *str) 49 { 50 return (bio_cb_write(bio, str, strlen(str))); 51 } 52 53 static long 54 bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr) 55 { 56 long ret = 1; 57 58 switch (cmd) { 59 case BIO_CTRL_GET_CLOSE: 60 ret = (long)bio->shutdown; 61 break; 62 case BIO_CTRL_SET_CLOSE: 63 bio->shutdown = (int)num; 64 break; 65 case BIO_CTRL_DUP: 66 case BIO_CTRL_FLUSH: 67 break; 68 case BIO_CTRL_INFO: 69 case BIO_CTRL_GET: 70 case BIO_CTRL_SET: 71 default: 72 ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); 73 } 74 75 return (ret); 76 } 77 78 static int 79 bio_cb_write(BIO *bio, const char *buf, int num) 80 { 81 struct tls *ctx = bio->ptr; 82 int rv; 83 84 BIO_clear_retry_flags(bio); 85 rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg); 86 if (rv == TLS_WANT_POLLIN) { 87 BIO_set_retry_read(bio); 88 rv = -1; 89 } else if (rv == TLS_WANT_POLLOUT) { 90 BIO_set_retry_write(bio); 91 rv = -1; 92 } 93 return (rv); 94 } 95 96 static int 97 bio_cb_read(BIO *bio, char *buf, int size) 98 { 99 struct tls *ctx = bio->ptr; 100 int rv; 101 102 BIO_clear_retry_flags(bio); 103 rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg); 104 if (rv == TLS_WANT_POLLIN) { 105 BIO_set_retry_read(bio); 106 rv = -1; 107 } else if (rv == TLS_WANT_POLLOUT) { 108 BIO_set_retry_write(bio); 109 rv = -1; 110 } 111 return (rv); 112 } 113 114 int 115 tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb, 116 void *cb_arg) 117 { 118 int rv = -1; 119 BIO *bio; 120 121 if (read_cb == NULL || write_cb == NULL) { 122 tls_set_errorx(ctx, "no callbacks provided"); 123 goto err; 124 } 125 126 ctx->read_cb = read_cb; 127 ctx->write_cb = write_cb; 128 ctx->cb_arg = cb_arg; 129 130 if ((bio = BIO_new(bio_s_cb())) == NULL) { 131 tls_set_errorx(ctx, "failed to create callback i/o"); 132 goto err; 133 } 134 bio->ptr = ctx; 135 bio->init = 1; 136 137 SSL_set_bio(ctx->ssl_conn, bio, bio); 138 139 rv = 0; 140 141 err: 142 return (rv); 143 } 144