1 /**
2  * @file openssl/tls_tcp.c TLS/TCP backend using OpenSSL
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 
7 #include <openssl/ssl.h>
8 #include <openssl/err.h>
9 #include <re_types.h>
10 #include <re_fmt.h>
11 #include <re_mem.h>
12 #include <re_mbuf.h>
13 #include <re_main.h>
14 #include <re_sa.h>
15 #include <re_net.h>
16 #include <re_srtp.h>
17 #include <re_tcp.h>
18 #include <re_tls.h>
19 #include "tls.h"
20 
21 
22 #define DEBUG_MODULE "tls"
23 #define DEBUG_LEVEL 5
24 #include <re_dbg.h>
25 
26 
27 /* NOTE: shadow struct defined in tls_*.c */
28 struct tls_conn {
29 	SSL *ssl;
30 #ifdef TLS_BIO_OPAQUE
31 	BIO_METHOD *biomet;
32 #endif
33 	BIO *sbio_out;
34 	BIO *sbio_in;
35 	struct tcp_helper *th;
36 	struct tcp_conn *tcp;
37 	bool active;
38 	bool up;
39 };
40 
41 
42 static void destructor(void *arg)
43 {
44 	struct tls_conn *tc = arg;
45 
46 	if (tc->ssl) {
47 		int r = SSL_shutdown(tc->ssl);
48 		if (r <= 0)
49 			ERR_clear_error();
50 
51 		SSL_free(tc->ssl);
52 	}
53 
54 #ifdef TLS_BIO_OPAQUE
55 	if (tc->biomet)
56 		BIO_meth_free(tc->biomet);
57 #endif
58 
59 	mem_deref(tc->th);
60 	mem_deref(tc->tcp);
61 }
62 
63 
64 static int bio_create(BIO *b)
65 {
66 #ifdef TLS_BIO_OPAQUE
67 	BIO_set_init(b, 1);
68 	BIO_set_data(b, NULL);
69 	BIO_set_flags(b, 0);
70 #else
71 	b->init  = 1;
72 	b->num   = 0;
73 	b->ptr   = NULL;
74 	b->flags = 0;
75 #endif
76 
77 	return 1;
78 }
79 
80 
81 static int bio_destroy(BIO *b)
82 {
83 	if (!b)
84 		return 0;
85 
86 #ifdef TLS_BIO_OPAQUE
87 	BIO_set_init(b, 0);
88 	BIO_set_data(b, NULL);
89 	BIO_set_flags(b, 0);
90 #else
91 	b->ptr   = NULL;
92 	b->init  = 0;
93 	b->flags = 0;
94 #endif
95 
96 	return 1;
97 }
98 
99 
100 static int bio_write(BIO *b, const char *buf, int len)
101 {
102 #ifdef TLS_BIO_OPAQUE
103 	struct tls_conn *tc = BIO_get_data(b);
104 #else
105 	struct tls_conn *tc = b->ptr;
106 #endif
107 	struct mbuf mb;
108 	int err;
109 
110 	mb.buf = (void *)buf;
111 	mb.pos = 0;
112 	mb.end = mb.size = len;
113 
114 	err = tcp_send_helper(tc->tcp, &mb, tc->th);
115 	if (err)
116 		return -1;
117 
118 	return len;
119 }
120 
121 
122 static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
123 {
124 	(void)b;
125 	(void)num;
126 	(void)ptr;
127 
128 	if (cmd == BIO_CTRL_FLUSH) {
129 		/* The OpenSSL library needs this */
130 		return 1;
131 	}
132 
133 	return 0;
134 }
135 
136 
137 #ifdef TLS_BIO_OPAQUE
138 
139 static BIO_METHOD *bio_method_tcp(void)
140 {
141 	BIO_METHOD *method;
142 
143 	method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "tcp_send");
144 	if (!method) {
145 		DEBUG_WARNING("alloc: BIO_meth_new() failed\n");
146 		ERR_clear_error();
147 		return NULL;
148 	}
149 
150 	BIO_meth_set_write(method, bio_write);
151 	BIO_meth_set_ctrl(method, bio_ctrl);
152 	BIO_meth_set_create(method, bio_create);
153 	BIO_meth_set_destroy(method, bio_destroy);
154 
155 	return method;
156 }
157 
158 #else
159 
160 static struct bio_method_st bio_tcp_send = {
161 	BIO_TYPE_SOURCE_SINK,
162 	"tcp_send",
163 	bio_write,
164 	0,
165 	0,
166 	0,
167 	bio_ctrl,
168 	bio_create,
169 	bio_destroy,
170 	0
171 };
172 
173 #endif
174 
175 
176 static int tls_connect(struct tls_conn *tc)
177 {
178 	int err = 0, r;
179 
180 	ERR_clear_error();
181 
182 	r = SSL_connect(tc->ssl);
183 	if (r <= 0) {
184 		const int ssl_err = SSL_get_error(tc->ssl, r);
185 
186 		ERR_clear_error();
187 
188 		switch (ssl_err) {
189 
190 		case SSL_ERROR_WANT_READ:
191 			break;
192 
193 		default:
194 			DEBUG_WARNING("connect: error (r=%d, ssl_err=%d)\n",
195 				      r, ssl_err);
196 			err = EPROTO;
197 			break;
198 		}
199 	}
200 
201 	return err;
202 }
203 
204 
205 static int tls_accept(struct tls_conn *tc)
206 {
207 	int err = 0, r;
208 
209 	ERR_clear_error();
210 
211 	r = SSL_accept(tc->ssl);
212 	if (r <= 0) {
213 		const int ssl_err = SSL_get_error(tc->ssl, r);
214 
215 		ERR_clear_error();
216 
217 		switch (ssl_err) {
218 
219 		case SSL_ERROR_WANT_READ:
220 			break;
221 
222 		default:
223 			DEBUG_WARNING("accept error: (r=%d, ssl_err=%d)\n",
224 				      r, ssl_err);
225 			err = EPROTO;
226 			break;
227 		}
228 	}
229 
230 	return err;
231 }
232 
233 
234 static bool estab_handler(int *err, bool active, void *arg)
235 {
236 	struct tls_conn *tc = arg;
237 
238 	DEBUG_INFO("tcp established (active=%u)\n", active);
239 
240 	if (!active)
241 		return true;
242 
243 	tc->active = true;
244 	*err = tls_connect(tc);
245 
246 	return true;
247 }
248 
249 
250 static bool recv_handler(int *err, struct mbuf *mb, bool *estab, void *arg)
251 {
252 	struct tls_conn *tc = arg;
253 	int r;
254 
255 	/* feed SSL data to the BIO */
256 	r = BIO_write(tc->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb));
257 	if (r <= 0) {
258 		DEBUG_WARNING("recv: BIO_write %d\n", r);
259 		ERR_clear_error();
260 		*err = ENOMEM;
261 		return true;
262 	}
263 
264 	if (SSL_state(tc->ssl) != SSL_ST_OK) {
265 
266 		if (tc->up) {
267 			*err = EPROTO;
268 			return true;
269 		}
270 
271 		if (tc->active) {
272 			*err = tls_connect(tc);
273 		}
274 		else {
275 			*err = tls_accept(tc);
276 		}
277 
278 		DEBUG_INFO("state=0x%04x\n", SSL_state(tc->ssl));
279 
280 		/* TLS connection is established */
281 		if (SSL_state(tc->ssl) != SSL_ST_OK)
282 			return true;
283 
284 		*estab = true;
285 		tc->up = true;
286 	}
287 
288 	mbuf_set_pos(mb, 0);
289 
290 	for (;;) {
291 		int n;
292 
293 		if (mbuf_get_space(mb) < 4096) {
294 			*err = mbuf_resize(mb, mb->size + 8192);
295 			if (*err)
296 				return true;
297 		}
298 
299 		ERR_clear_error();
300 
301 		n = SSL_read(tc->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb));
302 		if (n <= 0) {
303 			const int ssl_err = SSL_get_error(tc->ssl, n);
304 
305 			ERR_clear_error();
306 
307 			switch (ssl_err) {
308 
309 			case SSL_ERROR_WANT_READ:
310 				break;
311 
312 			case SSL_ERROR_ZERO_RETURN:
313 				*err = ECONNRESET;
314 				return true;
315 
316 			default:
317 				*err = EPROTO;
318 				return true;
319 			}
320 
321 			break;
322 		}
323 
324 		mb->pos += n;
325 	}
326 
327 	mbuf_set_end(mb, mb->pos);
328 	mbuf_set_pos(mb, 0);
329 
330 	return false;
331 }
332 
333 
334 static bool send_handler(int *err, struct mbuf *mb, void *arg)
335 {
336 	struct tls_conn *tc = arg;
337 	int r;
338 
339 	ERR_clear_error();
340 
341 	r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb));
342 	if (r <= 0) {
343 		DEBUG_WARNING("SSL_write: %d\n", SSL_get_error(tc->ssl, r));
344 		ERR_clear_error();
345 		*err = EPROTO;
346 	}
347 
348 	return true;
349 }
350 
351 
352 /**
353  * Start TLS on a TCP-connection
354  *
355  * @param ptc   Pointer to allocated TLS connectioon
356  * @param tls   TLS Context
357  * @param tcp   TCP Connection
358  * @param layer Protocol stack layer
359  *
360  * @return 0 if success, otherwise errorcode
361  */
362 int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, struct tcp_conn *tcp,
363 		  int layer)
364 {
365 	struct tls_conn *tc;
366 	int err;
367 
368 	if (!ptc || !tls || !tcp)
369 		return EINVAL;
370 
371 	tc = mem_zalloc(sizeof(*tc), destructor);
372 	if (!tc)
373 		return ENOMEM;
374 
375 	err = tcp_register_helper(&tc->th, tcp, layer, estab_handler,
376 				  send_handler, recv_handler, tc);
377 	if (err)
378 		goto out;
379 
380 	tc->tcp = mem_ref(tcp);
381 
382 #ifdef TLS_BIO_OPAQUE
383 	tc->biomet = bio_method_tcp();
384 	if (!tc->biomet) {
385 		err = ENOMEM;
386 		goto out;
387 	}
388 #endif
389 
390 	err = ENOMEM;
391 
392 	/* Connect the SSL socket */
393 	tc->ssl = SSL_new(tls->ctx);
394 	if (!tc->ssl) {
395 		DEBUG_WARNING("alloc: SSL_new() failed (ctx=%p)\n", tls->ctx);
396 		ERR_clear_error();
397 		goto out;
398 	}
399 
400 	tc->sbio_in = BIO_new(BIO_s_mem());
401 	if (!tc->sbio_in) {
402 		DEBUG_WARNING("alloc: BIO_new() failed\n");
403 		ERR_clear_error();
404 		goto out;
405 	}
406 
407 
408 #ifdef TLS_BIO_OPAQUE
409 	tc->sbio_out = BIO_new(tc->biomet);
410 #else
411 	tc->sbio_out = BIO_new(&bio_tcp_send);
412 #endif
413 	if (!tc->sbio_out) {
414 		DEBUG_WARNING("alloc: BIO_new_socket() failed\n");
415 		ERR_clear_error();
416 		BIO_free(tc->sbio_in);
417 		goto out;
418 	}
419 
420 #ifdef TLS_BIO_OPAQUE
421 	BIO_set_data(tc->sbio_out, tc);
422 #else
423 	tc->sbio_out->ptr = tc;
424 #endif
425 
426 	SSL_set_bio(tc->ssl, tc->sbio_in, tc->sbio_out);
427 
428 	err = 0;
429 
430  out:
431 	if (err)
432 		mem_deref(tc);
433 	else
434 		*ptc = tc;
435 
436 	return err;
437 }
438