xref: /dragonfly/crypto/libressl/tls/tls_bio_cb.c (revision 72c33676)
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