summaryrefslogtreecommitdiff
path: root/src/lib/libtls/tls_bio_cb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libtls/tls_bio_cb.c')
-rw-r--r--src/lib/libtls/tls_bio_cb.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/lib/libtls/tls_bio_cb.c b/src/lib/libtls/tls_bio_cb.c
new file mode 100644
index 0000000000..fc1c964912
--- /dev/null
+++ b/src/lib/libtls/tls_bio_cb.c
@@ -0,0 +1,224 @@
1/* $ID$ */
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 <stdlib.h>
19#include <unistd.h>
20#include <fcntl.h>
21
22#include "tls.h"
23#include "tls_internal.h"
24
25#include <openssl/bio.h>
26
27static int write_cb(BIO *b, const char *buf, int num);
28static int read_cb(BIO *b, char *buf, int size);
29static int puts_cb(BIO *b, const char *str);
30static long ctrl_cb(BIO *b, int cmd, long num, void *ptr);
31static int new_cb(BIO *b);
32static int free_cb(BIO *data);
33
34struct 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
40static 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
51static BIO_METHOD *
52bio_s_cb(void)
53{
54 return (&cb_method);
55}
56
57static int
58bio_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
67static int
68bio_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
77static int
78bio_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
86static int
87new_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
103static int
104free_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
121static int
122read_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
128static int
129write_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
135static int
136puts_cb(BIO *b, const char *str)
137{
138 int n;
139
140 n = strlen(str);
141 return (write_cb(b, str, n));
142}
143
144static long
145ctrl_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 break;
158 case BIO_CTRL_INFO:
159 case BIO_CTRL_GET:
160 case BIO_CTRL_SET:
161 default:
162 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
163 }
164
165 return (ret);
166}
167
168static int
169tls_bio_write_cb(BIO *h, const char *buf, int num, void *cb_arg)
170{
171 struct tls *ctx = cb_arg;
172 return (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
173}
174
175static int
176tls_bio_read_cb(BIO *h, char *buf, int size, void *cb_arg)
177{
178 struct tls *ctx = cb_arg;
179 return (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
180}
181
182static BIO *
183tls_get_new_cb_bio(struct tls *ctx)
184{
185 BIO *bcb;
186 if (ctx->read_cb == NULL || ctx->write_cb == NULL)
187 tls_set_errorx(ctx, "no callbacks registered");
188
189 bcb = BIO_new(bio_s_cb());
190 if (bcb == NULL) {
191 tls_set_errorx(ctx, "failed to create callback i/o");
192 return (NULL);
193 }
194
195 bio_set_write_cb(bcb, tls_bio_write_cb);
196 bio_set_read_cb(bcb, tls_bio_read_cb);
197 bio_set_cb_arg(bcb, ctx);
198
199 return (bcb);
200}
201
202int
203tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
204 void *cb_arg)
205{
206 int rv = -1;
207 BIO *bcb;
208 ctx->read_cb = read_cb;
209 ctx->write_cb = write_cb;
210 ctx->cb_arg = cb_arg;
211
212 bcb = tls_get_new_cb_bio(ctx);
213 if (bcb == NULL) {
214 tls_set_errorx(ctx, "failed to create callback i/o");
215 goto err;
216 }
217
218 SSL_set_bio(ctx->ssl_conn, bcb, bcb);
219
220 rv = 0;
221
222 err:
223 return (rv);
224}