]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/openssl.c
dlink -> rb_dlink
[irc/rqf/shadowircd.git] / libratbox / src / openssl.c
1 /*
2 * libratbox: a library used by ircd-ratbox and other things
3 * openssl.c: openssl related code
4 *
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
23 * $Id: commio.c 24808 2008-01-02 08:17:05Z androsyn $
24 */
25
26 #include <libratbox_config.h>
27 #include <ratbox_lib.h>
28
29 #ifdef HAVE_OPENSSL
30
31 #include <commio-int.h>
32 #include <commio-ssl.h>
33 #include <openssl/ssl.h>
34 #include <openssl/dh.h>
35 #include <openssl/err.h>
36 #include <openssl/rand.h>
37
38 static SSL_CTX *ssl_server_ctx;
39 static SSL_CTX *ssl_client_ctx;
40
41 static unsigned long get_last_err(void)
42 {
43 unsigned long t_err, err = 0;
44 err = ERR_get_error();
45 if(err == 0)
46 return 0;
47
48 while((t_err = ERR_get_error()) > 0)
49 err = t_err;
50
51 return err;
52 }
53
54 void
55 rb_ssl_shutdown(rb_fde_t * F)
56 {
57 int i;
58 if(F == NULL || F->ssl == NULL)
59 return;
60 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
61
62 for (i = 0; i < 4; i++)
63 {
64 if(SSL_shutdown((SSL *) F->ssl))
65 break;
66 }
67 get_last_err();
68 SSL_free((SSL *) F->ssl);
69 }
70
71 static void
72 rb_ssl_timeout(rb_fde_t * fd, void *notused)
73 {
74 rb_close(fd);
75 }
76
77
78 static void
79 rb_ssl_tryaccept(rb_fde_t * F, void *data)
80 {
81 int ssl_err;
82 lrb_assert(F->accept != NULL);
83
84 if(!SSL_is_init_finished((SSL *) F->ssl))
85 {
86 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
87 {
88 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
89 {
90 case SSL_ERROR_SYSCALL:
91 if(rb_ignore_errno(errno))
92 case SSL_ERROR_WANT_READ:
93 case SSL_ERROR_WANT_WRITE:
94 {
95 F->ssl_errno = get_last_err();
96 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
97 rb_ssl_tryaccept, NULL);
98 return;
99 }
100 default:
101 F->ssl_errno = get_last_err();
102 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
103 break;
104 }
105 return;
106 }
107 }
108 rb_settimeout(F, 0, NULL, NULL);
109 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
110
111 F->accept->callback(F, RB_OK, (struct sockaddr *) &F->accept->S, F->accept->addrlen,
112 F->accept->data);
113 rb_free(F->accept);
114 F->accept = NULL;
115
116 }
117
118 void
119 rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout)
120 {
121 int ssl_err;
122
123 new_F->type |= RB_FD_SSL;
124 new_F->ssl = SSL_new(ssl_server_ctx);
125 new_F->accept = rb_malloc(sizeof(struct acceptdata));
126
127 new_F->accept->callback = cb;
128 new_F->accept->data = data;
129 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
130
131 new_F->accept->addrlen = 0;
132 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
133 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
134 {
135 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
136 {
137 case SSL_ERROR_SYSCALL:
138 if(rb_ignore_errno(errno))
139 case SSL_ERROR_WANT_READ:
140 case SSL_ERROR_WANT_WRITE:
141 {
142 new_F->ssl_errno = get_last_err();
143 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
144 rb_ssl_tryaccept, NULL);
145 return;
146 }
147 default:
148 new_F->ssl_errno = get_last_err();
149 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
150 return;
151 }
152 }
153 else
154 {
155 rb_ssl_tryaccept(new_F, NULL);
156 }
157 }
158
159
160
161
162 void
163 rb_ssl_accept_setup(rb_fde_t * F, int new_fd, struct sockaddr *st, int addrlen)
164 {
165 rb_fde_t *new_F;
166 int ssl_err;
167
168 new_F = rb_find_fd(new_fd);
169 new_F->type |= RB_FD_SSL;
170 new_F->ssl = SSL_new(ssl_server_ctx);
171 new_F->accept = rb_malloc(sizeof(struct acceptdata));
172
173 new_F->accept->callback = F->accept->callback;
174 new_F->accept->data = F->accept->data;
175 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
176 memcpy(&new_F->accept->S, st, addrlen);
177 new_F->accept->addrlen = addrlen;
178
179 SSL_set_fd((SSL *) new_F->ssl, new_fd);
180 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
181 {
182 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
183 {
184 case SSL_ERROR_SYSCALL:
185 if(rb_ignore_errno(errno))
186 case SSL_ERROR_WANT_READ:
187 case SSL_ERROR_WANT_WRITE:
188 {
189 F->ssl_errno = get_last_err();
190 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
191 rb_ssl_tryaccept, NULL);
192 return;
193 }
194 default:
195 F->ssl_errno = get_last_err();
196 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
197 return;
198 }
199 }
200 else
201 {
202 rb_ssl_tryaccept(new_F, NULL);
203 }
204 }
205
206 static ssize_t
207 rb_ssl_read_or_write(int r_or_w, rb_fde_t * F, void *rbuf, const void *wbuf, size_t count)
208 {
209 ssize_t ret;
210 unsigned long err;
211 SSL *ssl = F->ssl;
212
213 if(r_or_w == 0)
214 ret = (ssize_t)SSL_read(ssl, rbuf, (int) count);
215 else
216 ret = (ssize_t)SSL_write(ssl, wbuf, (int) count);
217
218 if(ret < 0)
219 {
220 switch (SSL_get_error(ssl, ret))
221 {
222 case SSL_ERROR_WANT_READ:
223 errno = EAGAIN;
224 return RB_RW_SSL_NEED_READ;
225 case SSL_ERROR_WANT_WRITE:
226 errno = EAGAIN;
227 return RB_RW_SSL_NEED_WRITE;
228 case SSL_ERROR_ZERO_RETURN:
229 return 0;
230 case SSL_ERROR_SYSCALL:
231 err = get_last_err();
232 if(err == 0)
233 {
234 F->ssl_errno = 0;
235 return RB_RW_IO_ERROR;
236 }
237 break;
238 default:
239 err = get_last_err();
240 break;
241 }
242 F->ssl_errno = err;
243 if(err > 0)
244 {
245 errno = EIO; /* not great but... */
246 return RB_RW_SSL_ERROR;
247 }
248 return RB_RW_IO_ERROR;
249 }
250 return ret;
251 }
252
253 ssize_t
254 rb_ssl_read(rb_fde_t * F, void *buf, size_t count)
255 {
256 return rb_ssl_read_or_write(0, F, buf, NULL, count);
257 }
258
259 ssize_t
260 rb_ssl_write(rb_fde_t * F, const void *buf, size_t count)
261 {
262 return rb_ssl_read_or_write(1, F, NULL, buf, count);
263 }
264
265 int
266 rb_init_ssl(void)
267 {
268 int ret = 1;
269 SSL_load_error_strings();
270 SSL_library_init();
271 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
272 if(ssl_server_ctx == NULL)
273 {
274 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
275 ERR_error_string(ERR_get_error(), NULL));
276 ret = 0;
277 }
278 /* Disable SSLv2, make the client use our settings */
279 SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
280
281 ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
282
283 if(ssl_client_ctx == NULL)
284 {
285 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
286 ERR_error_string(ERR_get_error(), NULL));
287 ret = 0;
288 }
289 return ret;
290 }
291
292
293 int
294 rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
295 {
296 FILE *param;
297 DH *dh;
298 unsigned long err;
299 if(cert == NULL)
300 {
301 rb_lib_log("rb_setup_ssl_server: No certificate file");
302 return 0;
303 }
304 if(!SSL_CTX_use_certificate_file(ssl_server_ctx, cert, SSL_FILETYPE_PEM))
305 {
306 err = ERR_get_error();
307 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
308 ERR_error_string(err, NULL));
309 return 0;
310 }
311
312 if(keyfile == NULL)
313 {
314 rb_lib_log("rb_setup_ssl_server: No key file");
315 return 0;
316 }
317
318
319 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile, SSL_FILETYPE_PEM))
320 {
321 err = ERR_get_error();
322 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
323 ERR_error_string(err, NULL));
324 return 0;
325 }
326
327 if(dhfile != NULL)
328 {
329 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
330 param = fopen(dhfile, "r");
331 if(param != NULL)
332 {
333 dh = PEM_read_DHparams(param, NULL, NULL, NULL);
334 if(dh == NULL)
335 {
336 err = ERR_get_error();
337 rb_lib_log
338 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
339 param, ERR_error_string(err, NULL));
340 fclose(param);
341 return 0;
342 }
343 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
344 fclose(param);
345 }
346 }
347 return 1;
348 }
349
350 int
351 rb_ssl_listen(rb_fde_t * F, int backlog)
352 {
353 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
354 return listen(F->fd, backlog);
355 }
356
357 struct ssl_connect
358 {
359 CNCB *callback;
360 void *data;
361 int timeout;
362 };
363
364 static void
365 rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn)
366 {
367 F->connect->callback = sconn->callback;
368 F->connect->data = sconn->data;
369 rb_free(sconn);
370 rb_connect_callback(F, status);
371 }
372
373 static void
374 rb_ssl_tryconn_timeout_cb(rb_fde_t * F, void *data)
375 {
376 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
377 }
378
379 static void
380 rb_ssl_tryconn_cb(rb_fde_t * F, void *data)
381 {
382 struct ssl_connect *sconn = data;
383 int ssl_err;
384 if(!SSL_is_init_finished((SSL *) F->ssl))
385 {
386 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
387 {
388 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
389 {
390 case SSL_ERROR_SYSCALL:
391 if(rb_ignore_errno(errno))
392 case SSL_ERROR_WANT_READ:
393 case SSL_ERROR_WANT_WRITE:
394 {
395 F->ssl_errno = get_last_err();
396 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
397 rb_ssl_tryconn_cb, sconn);
398 return;
399 }
400 default:
401 F->ssl_errno = get_last_err();
402 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
403 return;
404 }
405 }
406 else
407 {
408 rb_ssl_connect_realcb(F, RB_OK, sconn);
409 }
410 }
411 }
412
413 static void
414 rb_ssl_tryconn(rb_fde_t * F, int status, void *data)
415 {
416 struct ssl_connect *sconn = data;
417 int ssl_err;
418 if(status != RB_OK)
419 {
420 rb_ssl_connect_realcb(F, status, sconn);
421 return;
422 }
423
424 F->type |= RB_FD_SSL;
425 F->ssl = SSL_new(ssl_client_ctx);
426 SSL_set_fd((SSL *) F->ssl, F->fd);
427
428 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
429 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
430 {
431 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
432 {
433 case SSL_ERROR_SYSCALL:
434 if(rb_ignore_errno(errno))
435 case SSL_ERROR_WANT_READ:
436 case SSL_ERROR_WANT_WRITE:
437 {
438 F->ssl_errno = get_last_err();
439 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
440 rb_ssl_tryconn_cb, sconn);
441 return;
442 }
443 default:
444 F->ssl_errno = get_last_err();
445 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
446 return;
447 }
448 }
449 else
450 {
451 rb_ssl_connect_realcb(F, RB_OK, sconn);
452 }
453 }
454
455 void
456 rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest,
457 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
458 {
459 struct ssl_connect *sconn;
460 if(F == NULL)
461 return;
462
463 sconn = rb_malloc(sizeof(struct ssl_connect));
464 sconn->data = data;
465 sconn->callback = callback;
466 sconn->timeout = timeout;
467 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
468
469 }
470
471 void
472 rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout)
473 {
474 struct ssl_connect *sconn;
475 int ssl_err;
476 if(F == NULL)
477 return;
478
479 sconn = rb_malloc(sizeof(struct ssl_connect));
480 sconn->data = data;
481 sconn->callback = callback;
482 sconn->timeout = timeout;
483 F->connect = rb_malloc(sizeof(struct conndata));
484 F->connect->callback = callback;
485 F->connect->data = data;
486 F->type |= RB_FD_SSL;
487 F->ssl = SSL_new(ssl_client_ctx);
488
489 SSL_set_fd((SSL *) F->ssl, F->fd);
490 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
491 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
492 {
493 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
494 {
495 case SSL_ERROR_SYSCALL:
496 if(rb_ignore_errno(errno))
497 case SSL_ERROR_WANT_READ:
498 case SSL_ERROR_WANT_WRITE:
499 {
500 F->ssl_errno = get_last_err();
501 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
502 rb_ssl_tryconn_cb, sconn);
503 return;
504 }
505 default:
506 F->ssl_errno = get_last_err();
507 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
508 return;
509 }
510 }
511 else
512 {
513 rb_ssl_connect_realcb(F, RB_OK, sconn);
514 }
515 }
516
517 int
518 rb_init_prng(const char *path, prng_seed_t seed_type)
519 {
520 if(seed_type == RB_PRNG_DEFAULT)
521 {
522 #ifdef WIN32
523 RAND_screen();
524 #endif
525 return RAND_status();
526 }
527 if(path == NULL)
528 return RAND_status();
529
530 switch (seed_type)
531 {
532 case RB_PRNG_EGD:
533 if(RAND_egd(path) == -1)
534 return -1;
535 break;
536 case RB_PRNG_FILE:
537 if(RAND_load_file(path, -1) == -1)
538 return -1;
539 break;
540 #ifdef WIN32
541 case RB_PRNGWIN32:
542 RAND_screen();
543 break;
544 #endif
545 default:
546 return -1;
547 }
548
549 return RAND_status();
550 }
551
552 int
553 rb_get_random(void *buf, size_t length)
554 {
555 if(RAND_status())
556 {
557 if(RAND_bytes(buf, length) > 0)
558 return 1;
559 }
560 else
561 {
562 if(RAND_pseudo_bytes(buf, length) >= 0)
563 return 1;
564 }
565 return 0;
566 }
567
568
569 const char *
570 rb_get_ssl_strerror(rb_fde_t * F)
571 {
572 return ERR_error_string(F->ssl_errno, NULL);
573 }
574
575 int
576 rb_supports_ssl(void)
577 {
578 return 1;
579 }
580
581 #endif /* HAVE_OPESSL */