6a337beba32ba708150d50ff69cbdd2517c5c49b
[project/ustream-ssl.git] / ustream-ssl.c
1 #include <errno.h>
2
3 #include <openssl/ssl.h>
4 #include <openssl/err.h>
5
6 #include <libubox/ustream.h>
7 #include "ustream-io.h"
8 #include "ustream-ssl.h"
9
10 static void ssl_init(void)
11 {
12 static bool _init = false;
13
14 if (_init)
15 return;
16
17 SSL_load_error_strings();
18 SSL_library_init();
19
20 _init = true;
21 }
22
23 static void ustream_ssl_error_cb(struct uloop_timeout *t)
24 {
25 struct ustream_ssl *us = container_of(t, struct ustream_ssl, error_timer);
26 static char buffer[128];
27 int error = us->error;
28
29 if (us->notify_error)
30 us->notify_error(us, error, ERR_error_string(us->error, buffer));
31 }
32
33 static void ustream_ssl_error(struct ustream_ssl *us, int error)
34 {
35 us->error = error;
36 uloop_timeout_set(&us->error_timer, 0);
37 }
38
39 static void ustream_ssl_check_conn(struct ustream_ssl *us)
40 {
41 int ret;
42
43 if (us->connected || us->error)
44 return;
45
46 if (us->server)
47 ret = SSL_accept(us->ssl);
48 else
49 ret = SSL_connect(us->ssl);
50
51 if (ret == 1) {
52 us->connected = true;
53 if (us->notify_connected)
54 us->notify_connected(us);
55 return;
56 }
57
58 ret = SSL_get_error(us->ssl, ret);
59 if (ret == SSL_ERROR_WANT_READ || ret == SSL_ERROR_WANT_WRITE)
60 return;
61
62 ustream_ssl_error(us, ret);
63 }
64
65 static void ustream_ssl_notify_read(struct ustream *s, int bytes)
66 {
67 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
68 char *buf;
69 int wr = 0, len, ret;
70
71 ustream_ssl_check_conn(us);
72 if (!us->connected || us->error)
73 return;
74
75 buf = ustream_reserve(&us->stream, 1, &len);
76 if (!len)
77 return;
78
79 do {
80 ret = SSL_read(us->ssl, buf, len);
81 if (ret < 0) {
82 ret = SSL_get_error(us->ssl, ret);
83
84 if (ret == SSL_ERROR_WANT_READ)
85 break;
86
87 ustream_ssl_error(us, ret);
88 break;
89 }
90 if (ret == 0) {
91 us->stream.eof = true;
92 ustream_state_change(&us->stream);
93 break;
94 }
95
96 buf += ret;
97 len -= ret;
98 wr += ret;
99 } while (1);
100
101 if (wr)
102 ustream_fill_read(&us->stream, wr);
103 }
104
105 static void ustream_ssl_notify_write(struct ustream *s, int bytes)
106 {
107 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
108
109 ustream_ssl_check_conn(us);
110 ustream_write_pending(s->next);
111 }
112
113 static void ustream_ssl_notify_state(struct ustream *s)
114 {
115 s->next->write_error = true;
116 ustream_state_change(s->next);
117 }
118
119 static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more)
120 {
121 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
122 int ret;
123
124 if (!us->connected || us->error)
125 return 0;
126
127 if (us->conn->w.data_bytes)
128 return 0;
129
130 ret = SSL_write(us->ssl, buf, len);
131 if (ret < 0) {
132 int err = SSL_get_error(us->ssl, ret);
133 if (err == SSL_ERROR_WANT_WRITE)
134 return 0;
135 }
136
137 return ret;
138 }
139
140 static void ustream_ssl_set_read_blocked(struct ustream *s)
141 {
142 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
143
144 ustream_set_read_blocked(us->conn, !!s->read_blocked);
145 }
146
147 static void ustream_ssl_free(struct ustream *s)
148 {
149 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
150
151 if (us->conn) {
152 us->conn->next = NULL;
153 us->conn->notify_read = NULL;
154 us->conn->notify_write = NULL;
155 us->conn->notify_state = NULL;
156 }
157
158 uloop_timeout_cancel(&us->error_timer);
159 SSL_shutdown(us->ssl);
160 SSL_free(us->ssl);
161 us->ctx = NULL;
162 us->ssl = NULL;
163 us->conn = NULL;
164 us->connected = false;
165 us->error = false;
166 }
167
168 static void ustream_ssl_stream_init(struct ustream_ssl *us)
169 {
170 struct ustream *conn = us->conn;
171 struct ustream *s = &us->stream;
172
173 conn->notify_read = ustream_ssl_notify_read;
174 conn->notify_write = ustream_ssl_notify_write;
175 conn->notify_state = ustream_ssl_notify_state;
176
177 s->free = ustream_ssl_free;
178 s->write = ustream_ssl_write;
179 s->set_read_blocked = ustream_ssl_set_read_blocked;
180 ustream_init_defaults(s);
181 }
182
183 void *ustream_ssl_context_new(bool server)
184 {
185 #ifdef CYASSL_OPENSSL_H_
186 SSL_METHOD *m;
187 #else
188 const SSL_METHOD *m;
189 #endif
190 SSL_CTX *c;
191
192 ssl_init();
193
194 #ifdef CYASSL_OPENSSL_H_
195 if (server)
196 m = SSLv23_server_method();
197 else
198 m = SSLv23_client_method();
199 #else
200 if (server)
201 m = TLSv1_server_method();
202 else
203 m = TLSv1_client_method();
204 #endif
205
206 c = SSL_CTX_new(m);
207 if (!c)
208 return NULL;
209
210 if (server)
211 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
212
213 return c;
214 }
215
216 int ustream_ssl_context_set_crt_file(void *ctx, const char *file)
217 {
218 int ret;
219
220 ret = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_PEM);
221 if (ret < 1)
222 ret = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_ASN1);
223
224 return ret;
225 }
226
227 int ustream_ssl_context_set_key_file(void *ctx, const char *file)
228 {
229 int ret;
230
231 ret = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM);
232 if (ret < 1)
233 ret = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_ASN1);
234
235 return ret;
236 }
237
238 void ustream_ssl_context_free(void *ctx)
239 {
240 SSL_CTX_free(ctx);
241 }
242
243 int ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, void *ctx, bool server)
244 {
245 us->error_timer.cb = ustream_ssl_error_cb;
246 us->server = server;
247 us->conn = conn;
248 us->ctx = ctx;
249
250 us->ssl = SSL_new(us->ctx);
251 if (!us->ssl)
252 return -ENOMEM;
253
254 conn->next = &us->stream;
255 ustream_set_io(ctx, us->ssl, conn);
256 ustream_ssl_stream_init(us);
257
258 return 0;
259 }