2 * ustream-ssl - library for SSL over ustream
4 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
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.
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.
22 #include <libubox/ustream.h>
24 #include "ustream-ssl.h"
25 #include "ustream-internal.h"
27 static void ustream_ssl_error_cb(struct uloop_timeout *t)
29 struct ustream_ssl *us = container_of(t, struct ustream_ssl, error_timer);
30 static char buffer[128];
31 int error = us->error;
34 us->notify_error(us, error, __ustream_ssl_strerror(us->error, buffer, sizeof(buffer)));
37 static void ustream_ssl_check_conn(struct ustream_ssl *us)
39 if (us->connected || us->error)
42 if (__ustream_ssl_connect(us) == U_SSL_OK) {
44 /* __ustream_ssl_connect() will also return U_SSL_OK when certificate
45 * verification failed!
47 * Applications may register a custom .notify_verify_error callback in the
48 * struct ustream_ssl which is called upon verification failures, but there
49 * is no straight forward way for the callback to terminate the connection
50 * initiation right away, e.g. through a true or false return value.
52 * Instead, existing implementations appear to set .eof field of the underlying
53 * ustream in the hope that this inhibits further operations on the stream.
55 * Declare this informal behaviour "official" and check for the state of the
56 * .eof member after __ustream_ssl_connect() returned, and do not write the
57 * pending data if it is set to true.
64 if (us->notify_connected)
65 us->notify_connected(us);
66 ustream_write_pending(&us->stream);
70 static bool __ustream_ssl_poll(struct ustream *s)
72 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
77 ustream_ssl_check_conn(us);
78 if (!us->connected || us->error)
82 buf = ustream_reserve(&us->stream, 1, &len);
86 ret = __ustream_ssl_read(us, buf, len);
93 us->stream.eof = true;
94 ustream_state_change(&us->stream);
97 ustream_fill_read(&us->stream, ret);
106 static void ustream_ssl_notify_read(struct ustream *s, int bytes)
108 __ustream_ssl_poll(s);
111 static void ustream_ssl_notify_write(struct ustream *s, int bytes)
113 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
115 ustream_ssl_check_conn(us);
116 ustream_write_pending(s->next);
119 static void ustream_ssl_notify_state(struct ustream *s)
121 s->next->write_error = true;
122 ustream_state_change(s->next);
125 static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more)
127 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
129 if (!us->connected || us->error)
132 if (us->conn->w.data_bytes)
135 return __ustream_ssl_write(us, buf, len);
138 static void ustream_ssl_set_read_blocked(struct ustream *s)
140 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
142 ustream_set_read_blocked(us->conn, !!s->read_blocked);
145 static void ustream_ssl_free(struct ustream *s)
147 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
150 us->conn->next = NULL;
151 us->conn->notify_read = NULL;
152 us->conn->notify_write = NULL;
153 us->conn->notify_state = NULL;
156 uloop_timeout_cancel(&us->error_timer);
157 __ustream_ssl_session_free(us->ssl);
164 us->connected = false;
166 us->valid_cert = false;
167 us->valid_cn = false;
170 static bool ustream_ssl_poll(struct ustream *s)
172 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
175 fd_poll = ustream_poll(us->conn);
176 return __ustream_ssl_poll(us->conn) || fd_poll;
179 static void ustream_ssl_stream_init(struct ustream_ssl *us)
181 struct ustream *conn = us->conn;
182 struct ustream *s = &us->stream;
184 conn->notify_read = ustream_ssl_notify_read;
185 conn->notify_write = ustream_ssl_notify_write;
186 conn->notify_state = ustream_ssl_notify_state;
188 s->free = ustream_ssl_free;
189 s->write = ustream_ssl_write;
190 s->poll = ustream_ssl_poll;
191 s->set_read_blocked = ustream_ssl_set_read_blocked;
192 ustream_init_defaults(s);
195 static int _ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server)
197 us->error_timer.cb = ustream_ssl_error_cb;
202 #if defined(HAVE_WOLFSSL) && defined(NO_WOLFSSL_SSLSETIO_SEND_RECV)
203 ustream_set_io(ctx, NULL, conn);
205 us->ssl = __ustream_ssl_session_new(us->ctx);
209 conn->next = &us->stream;
210 ustream_set_io(ctx, us->ssl, conn);
211 ustream_ssl_stream_init(us);
214 __ustream_ssl_set_server_name(us);
216 ustream_ssl_check_conn(us);
221 static int _ustream_ssl_set_peer_cn(struct ustream_ssl *us, const char *name)
223 us->peer_cn = strdup(name);
224 __ustream_ssl_update_peer_cn(us);
229 const struct ustream_ssl_ops ustream_ssl_ops = {
230 .context_new = __ustream_ssl_context_new,
231 .context_set_crt_file = __ustream_ssl_set_crt_file,
232 .context_set_key_file = __ustream_ssl_set_key_file,
233 .context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file,
234 .context_set_ciphers = __ustream_ssl_set_ciphers,
235 .context_free = __ustream_ssl_context_free,
236 .init = _ustream_ssl_init,
237 .set_peer_cn = _ustream_ssl_set_peer_cn,