1013bf733918ad94e7dad39a0faae64cff6de316
[sip-router] / modules / tls / tls_bio.c
1 /* 
2  * $Id$
3  * 
4  * Copyright (C) 2010 iptelorg GmbH
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /** openssl BIOs for reading/writing via a fixed memory buffer.
19  * @file /home/andrei/sr.git/modules/tls/tls_bio.c
20  * @ingroup tls
21  * @Module: @ref tls
22  */
23 /*
24  * History:
25  * --------
26  *  2010-03-25  initial version (andrei)
27  *  2010-05-20  emulate EAGAIN on null rd/wr memory buffer; handle some
28  *              needed commands in ctrl; debug support (TLS_BIO_DBG) (andrei)
29 */
30
31 #include "tls_bio.h"
32 #include "../../compiler_opt.h"
33 #include "../../dprint.h"
34 #include "../../ut.h"
35 #include "tls_cfg.h"
36
37 /* 0xf2 should be unused (as of openssl 1.0.0 max.
38    internal defined BIO is 23) */
39 #define BIO_TYPE_TLS_MBUF       (BIO_TYPE_SOURCE_SINK | 0xf2)
40
41 /* debugging */
42 #ifdef NO_TLS_BIO_DEBUG
43 #undef TLS_BIO_DEBUG
44 #endif
45 #ifdef TLS_BIO_DEBUG
46         #ifdef __SUNPRO_C
47                 #define TLS_BIO_DBG(...) \
48                         LOG_(DEFAULT_FACILITY, cfg_get(tls, tls_cfg, debug),\
49                                         "tls_BIO: " LOC_INFO,  __VA_ARGS__)
50         #else
51                 #define TLS_BIO_DBG(args...) \
52                         LOG_(DEFAULT_FACILITY, cfg_get(tls, tls_cfg, debug),\
53                                         "tls_BIO: " LOC_INFO, ## args)
54         #endif /* __SUNPRO_c */
55 #else /* TLS_BIO_DEBUG */
56         #ifdef __SUNPRO_C
57                 #define TLS_BIO_DBG(...)
58         #else
59                 #define TLS_BIO_DBG(fmt, args...)
60         #endif /* __SUNPRO_c */
61 #endif /* TLS_BIO_DEBUG */
62
63
64 static int tls_bio_mbuf_new(BIO* b);
65 static int tls_bio_mbuf_free(BIO* b);
66 static int tls_bio_mbuf_write(BIO* b, const char* buf, int num);
67 static int tls_bio_mbuf_read(BIO* b, char* buf, int num);
68 static int tls_bio_mbuf_puts(BIO* b, const char* s);
69 static long tls_bio_mbuf_ctrl(BIO* b, int cmd, long arg1, void* arg2);
70
71
72 static BIO_METHOD tls_mbuf_method = {
73         BIO_TYPE_TLS_MBUF,      /* type */
74         "sr_tls_mbuf",          /* name */
75         tls_bio_mbuf_write,     /* write function */
76         tls_bio_mbuf_read,      /* read function */
77         tls_bio_mbuf_puts,      /* puts function */
78         0,                                      /* gets function */
79         tls_bio_mbuf_ctrl,      /* ctrl function */
80         tls_bio_mbuf_new,       /* create(new) function */
81         tls_bio_mbuf_free,      /* destroy(free) function */
82         0                                       /* ctrl callback */
83 };
84
85
86 /** returns a custom tls_mbuf BIO. */
87 BIO_METHOD* tls_BIO_mbuf(void)
88 {
89         return &tls_mbuf_method;
90 }
91
92
93
94 /** create an initialize a new tls_BIO_mbuf.
95  * @return new BIO on success (!=0), 0 on error.
96  */
97 BIO* tls_BIO_new_mbuf(struct tls_mbuf* rd, struct tls_mbuf* wr)
98 {
99         BIO* ret;
100         
101         TLS_BIO_DBG("tls_BIO_new_mbuf called (%p, %p)\n", rd, wr);
102         ret = BIO_new(tls_BIO_mbuf());
103         if (unlikely(ret == 0))
104                 return 0;
105         if (unlikely(tls_BIO_mbuf_set(ret, rd, wr) == 0)) {
106                 BIO_free(ret);
107                 return 0;
108         }
109         return ret;
110 }
111
112
113
114 /** sets the read and write mbuf for an  mbuf BIO.
115  * @return 1 on success, 0 on error (openssl BIO convention).
116  */
117 int tls_BIO_mbuf_set(BIO* b, struct tls_mbuf* rd, struct tls_mbuf* wr)
118 {
119         struct tls_bio_mbuf_data* d;
120         
121         TLS_BIO_DBG("tls_BIO_mbuf_set called (%p => %p, %p)\n", b, rd, wr);
122         if (unlikely(b->ptr == 0)){
123                 BUG("null BIO ptr\n");
124                 return 0;
125         }
126         d = b->ptr;
127         d->rd = rd;
128         d->wr = wr;
129         b->init = 1;
130         return 1;
131 }
132
133
134
135 /** create a new BIO.
136  * (internal openssl use via the tls_mbuf method)
137  * @return 1 on success, 0 on error.
138  */
139 static int tls_bio_mbuf_new(BIO* b)
140 {
141         struct tls_bio_mbuf_data* d;
142         
143         TLS_BIO_DBG("tls_bio_mbuf_new called (%p)\n", b);
144         b->init = 0; /* not initialized yet */
145         b->num = 0;
146         b->ptr = 0;
147         b->flags = 0;
148         d = OPENSSL_malloc(sizeof(*d));
149         if (unlikely(d == 0))
150                 return 0;
151         d->rd = 0;
152         d->wr = 0;
153         b->ptr = d;
154         return 1;
155 }
156
157
158
159 /** destroy a tls mbuf BIO.
160  * (internal openssl use via the tls_mbuf method)
161  * @return 1 on success, 0 on error.
162  */
163 static int tls_bio_mbuf_free(BIO* b)
164 {
165         TLS_BIO_DBG("tls_bio_mbuf_free called (%p)\n", b);
166         if (unlikely( b == 0))
167                         return 0;
168         if (likely(b->ptr)){
169                 OPENSSL_free(b->ptr);
170                 b->ptr = 0;
171                 b->init = 0;
172         }
173         return 1;
174 }
175
176
177
178 /** read from a mbuf.
179  * (internal openssl use via the tls_mbuf method)
180  * @return bytes read on success (0< ret <=dst_len), -1 on empty buffer & sets
181  *  should_retry_read, -1 on some other errors (w/o should_retry_read set).
182  */
183 static int tls_bio_mbuf_read(BIO* b, char* dst, int dst_len)
184 {
185         struct tls_bio_mbuf_data* d;
186         struct tls_mbuf* rd;
187         int ret;
188         
189         ret = 0;
190         if (likely(dst)) {
191                 d= b->ptr;
192                 BIO_clear_retry_flags(b);
193                 if (unlikely(d == 0 || d->rd->buf == 0)) {
194                         if (d == 0)
195                                 BUG("tls_BIO_mbuf %p: read called with null b->ptr\n", b);
196                         else {
197                                 /* this form of calling read with a null buffer is used
198                                    as a shortcut when no data is available =>
199                                    simulate EAGIAN/WANT_READ */
200                                 TLS_BIO_DBG("read (%p, %p, %d) called with null read buffer"
201                                                 "(%p->%p) => simulating EAGAIN/WANT_READ\n",
202                                                 b, dst, dst_len, d, d->rd);
203                                 BIO_set_retry_read(b);
204                         }
205                         return -1;
206                 }
207                 rd = d->rd;
208                 if (unlikely(rd->used == rd->pos && dst_len)) {
209                         /* mimic non-blocking read behaviour */
210                         TLS_BIO_DBG("read (%p, %p, %d) called with full rd (%d)"
211                                                 " => simulating EAGAIN/WANT_READ\n",
212                                                 b, dst, dst_len, rd->used);
213                         BIO_set_retry_read(b);
214                         return -1;
215                 }
216                 ret = MIN_int(rd->used - rd->pos, dst_len);
217                 /* copy data from rd.buf into dst */
218                 memcpy(dst, rd->buf+rd->pos, ret);
219                 TLS_BIO_DBG("read(%p, %p, %d) called with rd=%p pos=%d => %d bytes\n",
220                                                 b, dst, dst_len, rd->buf, rd->pos, ret);
221                 rd->pos += ret;
222 /*              if (unlikely(rd->pos < rd->used))
223                         BIO_set_retry_read(b);
224 */
225         }
226         return ret;
227 }
228
229
230
231 /** write to a mbuf.
232  * (internal openssl use via the tls_mbuf method)
233  * @return bytes written on success (0<= ret <=src_len), -1 on error or buffer
234  * full (in this case sets should_retry_write).
235  */
236 static int tls_bio_mbuf_write(BIO* b, const char* src, int src_len)
237 {
238         struct tls_bio_mbuf_data* d;
239         struct tls_mbuf* wr;
240         int ret;
241         
242         ret = 0;
243         d= b->ptr;
244         BIO_clear_retry_flags(b);
245         if (unlikely(d == 0 || d->wr->buf == 0)) {
246                 if (d == 0)
247                         BUG("tls_BIO_mbuf %p: write called with null b->ptr\n", b);
248                 else {
249                         /* this form of calling write with a null buffer is used
250                            as a shortcut when no data is available =>
251                            simulate EAGAIN/WANT_WRITE */
252                         TLS_BIO_DBG("write (%p, %p, %d) called with null buffer"
253                                         " => simulating WANT_WRITE\n", b, src, src_len);
254                         BIO_set_retry_write(b);
255                 }
256                 return -1;
257         }
258         wr = d->wr;
259         if (unlikely(wr->size == wr->used && src_len)) {
260                 /* mimic non-blocking socket behaviour */
261                 TLS_BIO_DBG("write (%p, %p, %d) called with full wr buffer (%d)"
262                                         " => simulating WANT_WRITE\n", b, src, src_len, wr->used);
263                 BIO_set_retry_write(b);
264                 return -1;
265         }
266         ret = MIN_int(wr->size - wr->used, src_len);
267         memcpy(wr->buf + wr->used, src, ret);
268         wr->used += ret;
269 /*      if (unlikely(ret < src_len))
270                 BIO_set_retry_write();
271 */
272         TLS_BIO_DBG("write called (%p, %p, %d) => %d\n", b, src, src_len, ret);
273         return ret;
274 }
275
276
277
278 static long tls_bio_mbuf_ctrl(BIO* b, int cmd, long arg1, void* arg2)
279 {
280         long ret;
281         ret=0;
282         switch(cmd) {
283                 case BIO_C_SET_FD:
284                 case BIO_C_GET_FD:
285                         ret = -1; /* error, not supported */
286                         break;
287                 case BIO_CTRL_GET_CLOSE:
288                 case BIO_CTRL_SET_CLOSE:
289                         ret = 0;
290                         break;
291                 case BIO_CTRL_DUP:
292                 case BIO_CTRL_FLUSH:
293                         ret = 1;
294                         break;
295                 case BIO_CTRL_RESET:
296                 case BIO_C_FILE_SEEK:
297                 case BIO_C_FILE_TELL:
298                 case BIO_CTRL_INFO:
299                 case BIO_CTRL_PENDING:
300                 case BIO_CTRL_WPENDING:
301                 default:
302                         ret = 0;
303                         break;
304         }
305         TLS_BIO_DBG("ctrl called (%p, %d, %ld, %p) => %ld\n",
306                                 b, cmd, arg1, arg2, ret);
307         return ret;
308 }
309
310
311
312 static int tls_bio_mbuf_puts(BIO* b, const char* s)
313 {
314         int len;
315         
316         TLS_BIO_DBG("puts called (%p, %s)\n", b, s);
317         len=strlen(s);
318         return tls_bio_mbuf_write(b, s, len);
319 }
320
321
322
323 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */