• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ustream-ssl/ustream-ssl.c

  1 /*
  2  * ustream-ssl - library for SSL over ustream
  3  *
  4  * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
  5  *
  6  * Permission to use, copy, modify, and/or 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 
 19 #include <errno.h>
 20 #include <stdlib.h>
 21 #include <string.h>
 22 #include <libubox/ustream.h>
 23 
 24 #include "ustream-ssl.h"
 25 #include "ustream-internal.h"
 26 
 27 static void ustream_ssl_error_cb(struct uloop_timeout *t)
 28 {
 29         struct ustream_ssl *us = container_of(t, struct ustream_ssl, error_timer);
 30         static char buffer[128];
 31         int error = us->error;
 32 
 33         if (us->notify_error)
 34                 us->notify_error(us, error, __ustream_ssl_strerror(us->error, buffer, sizeof(buffer)));
 35 }
 36 
 37 static void ustream_ssl_check_conn(struct ustream_ssl *us)
 38 {
 39         struct ustream *s = &us->stream;
 40         struct ustream_free_guard guard;
 41         bool connected;
 42 
 43         if (us->connected || us->error || us->stream.eof)
 44                 return;
 45 
 46         /* the handshake may invoke notify_verify_error */
 47         ustream_free_guard_set(s, &guard);
 48         connected = __ustream_ssl_connect(us) == U_SSL_OK;
 49         if (ustream_free_guard_check(s, &guard))
 50                 return;
 51 
 52         if (!connected)
 53                 return;
 54 
 55         /* __ustream_ssl_connect() will also return U_SSL_OK when certificate
 56          * verification failed!
 57          *
 58          * Applications may register a custom .notify_verify_error callback in the
 59          * struct ustream_ssl which is called upon verification failures, but there
 60          * is no straight forward way for the callback to terminate the connection
 61          * initiation right away, e.g. through a true or false return value.
 62          *
 63          * Instead, existing implementations appear to set .eof field of the underlying
 64          * ustream in the hope that this inhibits further operations on the stream.
 65          *
 66          * Declare this informal behaviour "official" and check for the state of the
 67          * .eof member after __ustream_ssl_connect() returned, and do not write the
 68          * pending data if it is set to true.
 69          */
 70 
 71         if (us->stream.eof)
 72                 return;
 73 
 74         us->connected = true;
 75         if (us->notify_connected) {
 76                 ustream_free_guard_set(s, &guard);
 77                 us->notify_connected(us);
 78                 if (ustream_free_guard_check(s, &guard))
 79                         return;
 80         }
 81 
 82         ustream_write_pending(s);
 83 }
 84 
 85 static bool __ustream_ssl_poll(struct ustream_ssl *us)
 86 {
 87         struct ustream *s = &us->stream;
 88         struct ustream_free_guard guard;
 89         char *buf;
 90         int len, ret;
 91         bool more = false;
 92 
 93         ustream_free_guard_set(s, &guard);
 94         ustream_ssl_check_conn(us);
 95         if (ustream_free_guard_check(s, &guard))
 96                 return false;
 97 
 98         if (!us->connected || us->error)
 99                 return false;
100 
101         do {
102                 buf = ustream_reserve(s, 1, &len);
103                 if (!len)
104                         break;
105 
106                 ret = __ustream_ssl_read(us, buf, len);
107                 if (ret == U_SSL_PENDING) {
108                         if (us->conn) {
109                                 ustream_free_guard_set(s, &guard);
110                                 ustream_poll(us->conn);
111                                 if (ustream_free_guard_check(s, &guard))
112                                         return more;
113                         }
114                         ret = __ustream_ssl_read(us, buf, len);
115                 }
116 
117                 switch (ret) {
118                 case U_SSL_PENDING:
119                         return more;
120                 case U_SSL_ERROR:
121                         return false;
122                 case 0:
123                         s->eof = true;
124                         ustream_state_change(s);
125                         return false;
126                 default:
127                         ustream_free_guard_set(s, &guard);
128                         ustream_fill_read(s, ret);
129                         if (ustream_free_guard_check(s, &guard))
130                                 return more;
131 
132                         more = true;
133                         continue;
134                 }
135         } while (1);
136 
137         return more;
138 }
139 
140 static void ustream_ssl_notify_read(struct ustream *s, int bytes)
141 {
142         struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
143 
144         __ustream_ssl_poll(us);
145 }
146 
147 static void ustream_ssl_notify_write(struct ustream *s, int bytes)
148 {
149         struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
150         struct ustream_free_guard guard;
151 
152         ustream_free_guard_set(&us->stream, &guard);
153         ustream_ssl_check_conn(us);
154         if (ustream_free_guard_check(&us->stream, &guard))
155                 return;
156 
157         ustream_write_pending(s->next);
158 }
159 
160 static void ustream_ssl_notify_state(struct ustream *s)
161 {
162         s->next->write_error = true;
163         ustream_state_change(s->next);
164 }
165 
166 static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more)
167 {
168         struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
169         int ret;
170 
171         if (!us->connected || us->error)
172                 return 0;
173 
174         if (us->conn && us->conn->w.data_bytes)
175                 return 0;
176 
177         /* Data that the SSL library did not accept is buffered by the ustream
178          * core and retried from the buffers, i.e. with a different address and
179          * typically a different length. SSL write retry semantics require the
180          * retry to cover exactly the data of the failed call: with a shorter
181          * retry OpenSSL fails ("bad write retry"), while mbedTLS reports the
182          * retried length as written even though only the previously packaged
183          * record is sent, corrupting the stream. Cap the retry length to the
184          * length of the failed call to keep both libraries consistent.
185          */
186         if (us->pending_write > 0 && len > us->pending_write)
187                 len = us->pending_write;
188 
189         ret = __ustream_ssl_write(us, buf, len);
190         if (ret < 0) {
191                 us->pending_write = 0;
192                 return ret;
193         }
194 
195         us->pending_write = len - ret;
196 
197         return ret;
198 }
199 
200 static void ustream_ssl_set_read_blocked(struct ustream *s)
201 {
202         struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
203         unsigned int ev = ULOOP_WRITE | ULOOP_EDGE_TRIGGER;
204 
205         if (us->conn) {
206                 ustream_set_read_blocked(us->conn, !!s->read_blocked);
207                 return;
208         }
209 
210         if (!s->read_blocked)
211                 ev |= ULOOP_READ;
212 
213         uloop_fd_add(&us->fd, ev);
214 }
215 
216 static void ustream_ssl_free(struct ustream *s)
217 {
218         struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
219 
220         if (us->conn) {
221                 us->conn->next = NULL;
222                 us->conn->notify_read = NULL;
223                 us->conn->notify_write = NULL;
224                 us->conn->notify_state = NULL;
225         } else {
226                 uloop_fd_delete(&us->fd);
227         }
228 
229         uloop_timeout_cancel(&us->error_timer);
230         __ustream_ssl_session_free(us);
231         free(us->peer_cn);
232 
233         us->ctx = NULL;
234         us->ssl = NULL;
235         us->conn = NULL;
236         us->peer_cn = NULL;
237         us->connected = false;
238         us->error = false;
239         us->pending_write = 0;
240         us->valid_cert = false;
241         us->valid_cn = false;
242 }
243 
244 static bool ustream_ssl_poll(struct ustream *s)
245 {
246         struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
247         struct ustream_free_guard guard;
248         bool fd_poll = false;
249 
250         if (us->conn) {
251                 ustream_free_guard_set(s, &guard);
252                 fd_poll = ustream_poll(us->conn);
253                 if (ustream_free_guard_check(s, &guard))
254                         return fd_poll;
255         }
256 
257         return __ustream_ssl_poll(us) || fd_poll;
258 }
259 
260 static void ustream_ssl_fd_cb(struct uloop_fd *fd, unsigned int events)
261 {
262         struct ustream_ssl *us = container_of(fd, struct ustream_ssl, fd);
263 
264         __ustream_ssl_poll(us);
265 
266         if (!(events & ULOOP_WRITE))
267                 return;
268 
269         if (us->connected && !us->error && us->stream.w.data_bytes)
270                 ustream_write_pending(&us->stream);
271 }
272 
273 static void ustream_ssl_stream_init(struct ustream_ssl *us)
274 {
275         struct ustream *conn = us->conn;
276         struct ustream *s = &us->stream;
277 
278         if (conn) {
279                 conn->notify_read = ustream_ssl_notify_read;
280                 conn->notify_write = ustream_ssl_notify_write;
281                 conn->notify_state = ustream_ssl_notify_state;
282         } else {
283                 us->fd.cb = ustream_ssl_fd_cb;
284                 uloop_fd_add(&us->fd, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
285         }
286 
287         s->set_read_blocked = ustream_ssl_set_read_blocked;
288         s->free = ustream_ssl_free;
289         s->write = ustream_ssl_write;
290         s->poll = ustream_ssl_poll;
291         ustream_init_defaults(s);
292 }
293 
294 static int _ustream_ssl_init_common(struct ustream_ssl *us)
295 {
296         us->error_timer.cb = ustream_ssl_error_cb;
297 
298         us->ssl = __ustream_ssl_session_new(us->ctx);
299         if (!us->ssl)
300                 return -ENOMEM;
301 
302         ustream_set_io(us);
303         ustream_ssl_stream_init(us);
304 
305         if (us->server_name)
306                 __ustream_ssl_set_server_name(us);
307 
308         if (us->peer_cn && __ustream_ssl_update_peer_cn(us))
309                 return -ENOMEM;
310 
311         ustream_ssl_check_conn(us);
312 
313         return 0;
314 }
315 
316 static int _ustream_ssl_init_fd(struct ustream_ssl *us, int fd, struct ustream_ssl_ctx *ctx, bool server)
317 {
318         us->server = server;
319         us->ctx = ctx;
320         us->fd.fd = fd;
321 
322         /* Writes can block on the socket, so blocked data is buffered and
323          * retried one buffer chunk at a time. The first retried chunk must
324          * cover the record pending inside the SSL library, so it has to hold
325          * at least the maximum TLS plaintext fragment size.
326          */
327         if (!us->stream.w.buffer_len)
328                 us->stream.w.buffer_len = 16384;
329 
330         return _ustream_ssl_init_common(us);
331 }
332 
333 static int _ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server)
334 {
335         int ret;
336 
337         us->server = server;
338         us->ctx = ctx;
339 
340         us->conn = conn;
341         conn->r.max_buffers = 4;
342         conn->next = &us->stream;
343 
344         ret = _ustream_ssl_init_common(us);
345         if (ret) {
346                 conn->next = NULL;
347                 us->conn = NULL;
348         }
349 
350         return ret;
351 }
352 
353 static int _ustream_ssl_set_peer_cn(struct ustream_ssl *us, const char *name)
354 {
355         char *peer_cn = strdup(name);
356 
357         if (!peer_cn)
358                 return -ENOMEM;
359 
360         free(us->peer_cn);
361         us->peer_cn = peer_cn;
362 
363         if (us->ssl)
364                 return __ustream_ssl_update_peer_cn(us);
365 
366         return 0;
367 }
368 
369 const struct ustream_ssl_ops ustream_ssl_ops = {
370         .context_new = __ustream_ssl_context_new,
371         .context_set_crt_file = __ustream_ssl_set_crt_file,
372         .context_set_key_file = __ustream_ssl_set_key_file,
373         .context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file,
374         .context_set_ciphers = __ustream_ssl_set_ciphers,
375         .context_set_require_validation = __ustream_ssl_set_require_validation,
376         .context_set_debug = __ustream_ssl_set_debug,
377         .context_free = __ustream_ssl_context_free,
378         .init = _ustream_ssl_init,
379         .init_fd = _ustream_ssl_init_fd,
380         .set_peer_cn = _ustream_ssl_set_peer_cn,
381 };
382 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt