]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/openssl.c
d8efaa7b12d127b59a422e8f814b93f2ee2f8eea
[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 static int libratbox_index = -1;
41
42 static unsigned long get_last_err(void)
43 {
44 unsigned long t_err, err = 0;
45 err = ERR_get_error();
46 if(err == 0)
47 return 0;
48
49 while((t_err = ERR_get_error()) > 0)
50 err = t_err;
51
52 return err;
53 }
54
55 void
56 rb_ssl_shutdown(rb_fde_t * F)
57 {
58 int i;
59 if(F == NULL || F->ssl == NULL)
60 return;
61 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
62
63 for (i = 0; i < 4; i++)
64 {
65 if(SSL_shutdown((SSL *) F->ssl))
66 break;
67 }
68 get_last_err();
69 SSL_free((SSL *) F->ssl);
70 }
71
72 unsigned int
73 rb_ssl_handshake_count(rb_fde_t *F)
74 {
75 return F->handshake_count;
76 }
77
78 void
79 rb_ssl_clear_handshake_count(rb_fde_t *F)
80 {
81 F->handshake_count = 0;
82 }
83
84 static void
85 rb_ssl_timeout(rb_fde_t * F, void *notused)
86 {
87 lrb_assert(F->accept != NULL);
88 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
89 }
90
91
92 static void rb_ssl_info_callback(SSL *ssl, int where, int ret)
93 {
94 if(where & SSL_CB_HANDSHAKE_START)
95 {
96 rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index);
97 if(F == NULL)
98 return;
99 F->handshake_count++;
100 }
101 }
102
103 static void
104 rb_setup_ssl_cb(rb_fde_t *F)
105 {
106 SSL_set_ex_data(F->ssl, libratbox_index, (char *)F);
107 SSL_set_info_callback((SSL *)F->ssl, (void *)rb_ssl_info_callback);
108 }
109
110 static void
111 rb_ssl_tryaccept(rb_fde_t * F, void *data)
112 {
113 int ssl_err;
114 lrb_assert(F->accept != NULL);
115 int flags;
116 struct acceptdata *ad;
117
118 if(!SSL_is_init_finished((SSL *) F->ssl))
119 {
120 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
121 {
122 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
123 {
124 case SSL_ERROR_WANT_READ:
125 case SSL_ERROR_WANT_WRITE:
126 if(ssl_err == SSL_ERROR_WANT_WRITE)
127 flags = RB_SELECT_WRITE;
128 else
129 flags = RB_SELECT_READ;
130 F->ssl_errno = get_last_err();
131 rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
132 break;
133 case SSL_ERROR_SYSCALL:
134 F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
135 break;
136 default:
137 F->ssl_errno = get_last_err();
138 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
139 break;
140 }
141 return;
142 }
143 }
144 rb_settimeout(F, 0, NULL, NULL);
145 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
146
147 ad = F->accept;
148 F->accept = NULL;
149 ad->callback(F, RB_OK, (struct sockaddr *) &ad->S, ad->addrlen,
150 ad->data);
151 rb_free(ad);
152
153 }
154
155
156 static void
157 rb_ssl_accept_common(rb_fde_t *new_F)
158 {
159 int ssl_err;
160 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
161 {
162 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
163 {
164 case SSL_ERROR_SYSCALL:
165 if(rb_ignore_errno(errno))
166 case SSL_ERROR_WANT_READ:
167 case SSL_ERROR_WANT_WRITE:
168 {
169 new_F->ssl_errno = get_last_err();
170 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
171 rb_ssl_tryaccept, NULL);
172 return;
173 }
174 default:
175 new_F->ssl_errno = get_last_err();
176 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
177 return;
178 }
179 }
180 else
181 {
182 rb_ssl_tryaccept(new_F, NULL);
183 }
184 }
185
186 void
187 rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout)
188 {
189 new_F->type |= RB_FD_SSL;
190 new_F->ssl = SSL_new(ssl_server_ctx);
191 new_F->accept = rb_malloc(sizeof(struct acceptdata));
192
193 new_F->accept->callback = cb;
194 new_F->accept->data = data;
195 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
196
197 new_F->accept->addrlen = 0;
198 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
199 rb_setup_ssl_cb(new_F);
200 rb_ssl_accept_common(new_F);
201 }
202
203
204
205
206 void
207 rb_ssl_accept_setup(rb_fde_t * F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
208 {
209 new_F->type |= RB_FD_SSL;
210 new_F->ssl = SSL_new(ssl_server_ctx);
211 new_F->accept = rb_malloc(sizeof(struct acceptdata));
212
213 new_F->accept->callback = F->accept->callback;
214 new_F->accept->data = F->accept->data;
215 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
216 memcpy(&new_F->accept->S, st, addrlen);
217 new_F->accept->addrlen = addrlen;
218
219 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
220 rb_setup_ssl_cb(new_F);
221 rb_ssl_accept_common(new_F);
222 }
223
224 static ssize_t
225 rb_ssl_read_or_write(int r_or_w, rb_fde_t * F, void *rbuf, const void *wbuf, size_t count)
226 {
227 ssize_t ret;
228 unsigned long err;
229 SSL *ssl = F->ssl;
230
231 if(r_or_w == 0)
232 ret = (ssize_t)SSL_read(ssl, rbuf, (int) count);
233 else
234 ret = (ssize_t)SSL_write(ssl, wbuf, (int) count);
235
236 if(ret < 0)
237 {
238 switch (SSL_get_error(ssl, ret))
239 {
240 case SSL_ERROR_WANT_READ:
241 errno = EAGAIN;
242 return RB_RW_SSL_NEED_READ;
243 case SSL_ERROR_WANT_WRITE:
244 errno = EAGAIN;
245 return RB_RW_SSL_NEED_WRITE;
246 case SSL_ERROR_ZERO_RETURN:
247 return 0;
248 case SSL_ERROR_SYSCALL:
249 err = get_last_err();
250 if(err == 0)
251 {
252 F->ssl_errno = 0;
253 return RB_RW_IO_ERROR;
254 }
255 break;
256 default:
257 err = get_last_err();
258 break;
259 }
260 F->ssl_errno = err;
261 if(err > 0)
262 {
263 errno = EIO; /* not great but... */
264 return RB_RW_SSL_ERROR;
265 }
266 return RB_RW_IO_ERROR;
267 }
268 return ret;
269 }
270
271 ssize_t
272 rb_ssl_read(rb_fde_t * F, void *buf, size_t count)
273 {
274 return rb_ssl_read_or_write(0, F, buf, NULL, count);
275 }
276
277 ssize_t
278 rb_ssl_write(rb_fde_t * F, const void *buf, size_t count)
279 {
280 return rb_ssl_read_or_write(1, F, NULL, buf, count);
281 }
282
283 int
284 rb_init_ssl(void)
285 {
286 int ret = 1;
287 char libratbox_data[] = "libratbox data";
288 SSL_load_error_strings();
289 SSL_library_init();
290 libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL);
291 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
292 if(ssl_server_ctx == NULL)
293 {
294 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
295 ERR_error_string(ERR_get_error(), NULL));
296 ret = 0;
297 }
298 /* Disable SSLv2, make the client use our settings */
299 SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
300
301 ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
302
303 if(ssl_client_ctx == NULL)
304 {
305 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
306 ERR_error_string(ERR_get_error(), NULL));
307 ret = 0;
308 }
309 return ret;
310 }
311
312
313 int
314 rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
315 {
316 FILE *param;
317 DH *dh;
318 unsigned long err;
319 if(cert == NULL)
320 {
321 rb_lib_log("rb_setup_ssl_server: No certificate file");
322 return 0;
323 }
324 if(!SSL_CTX_use_certificate_file(ssl_server_ctx, cert, SSL_FILETYPE_PEM))
325 {
326 err = ERR_get_error();
327 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
328 ERR_error_string(err, NULL));
329 return 0;
330 }
331
332 if(keyfile == NULL)
333 {
334 rb_lib_log("rb_setup_ssl_server: No key file");
335 return 0;
336 }
337
338
339 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile, SSL_FILETYPE_PEM))
340 {
341 err = ERR_get_error();
342 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
343 ERR_error_string(err, NULL));
344 return 0;
345 }
346
347 if(dhfile != NULL)
348 {
349 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
350 param = fopen(dhfile, "r");
351 if(param != NULL)
352 {
353 dh = PEM_read_DHparams(param, NULL, NULL, NULL);
354 if(dh == NULL)
355 {
356 err = ERR_get_error();
357 rb_lib_log
358 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
359 param, ERR_error_string(err, NULL));
360 fclose(param);
361 return 0;
362 }
363 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
364 fclose(param);
365 }
366 }
367 return 1;
368 }
369
370 int
371 rb_ssl_listen(rb_fde_t * F, int backlog)
372 {
373 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
374 return listen(F->fd, backlog);
375 }
376
377 struct ssl_connect
378 {
379 CNCB *callback;
380 void *data;
381 int timeout;
382 };
383
384 static void
385 rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn)
386 {
387 F->connect->callback = sconn->callback;
388 F->connect->data = sconn->data;
389 rb_free(sconn);
390 rb_connect_callback(F, status);
391 }
392
393 static void
394 rb_ssl_tryconn_timeout_cb(rb_fde_t * F, void *data)
395 {
396 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
397 }
398
399 static void
400 rb_ssl_tryconn_cb(rb_fde_t * F, void *data)
401 {
402 struct ssl_connect *sconn = data;
403 int ssl_err;
404 if(!SSL_is_init_finished((SSL *) F->ssl))
405 {
406 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
407 {
408 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
409 {
410 case SSL_ERROR_SYSCALL:
411 if(rb_ignore_errno(errno))
412 case SSL_ERROR_WANT_READ:
413 case SSL_ERROR_WANT_WRITE:
414 {
415 F->ssl_errno = get_last_err();
416 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
417 rb_ssl_tryconn_cb, sconn);
418 return;
419 }
420 default:
421 F->ssl_errno = get_last_err();
422 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
423 return;
424 }
425 }
426 else
427 {
428 rb_ssl_connect_realcb(F, RB_OK, sconn);
429 }
430 }
431 }
432
433 static void
434 rb_ssl_tryconn(rb_fde_t * F, int status, void *data)
435 {
436 struct ssl_connect *sconn = data;
437 int ssl_err;
438 if(status != RB_OK)
439 {
440 rb_ssl_connect_realcb(F, status, sconn);
441 return;
442 }
443
444 F->type |= RB_FD_SSL;
445 F->ssl = SSL_new(ssl_client_ctx);
446 SSL_set_fd((SSL *) F->ssl, F->fd);
447 rb_setup_ssl_cb(F);
448 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
449 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
450 {
451 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
452 {
453 case SSL_ERROR_SYSCALL:
454 if(rb_ignore_errno(errno))
455 case SSL_ERROR_WANT_READ:
456 case SSL_ERROR_WANT_WRITE:
457 {
458 F->ssl_errno = get_last_err();
459 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
460 rb_ssl_tryconn_cb, sconn);
461 return;
462 }
463 default:
464 F->ssl_errno = get_last_err();
465 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
466 return;
467 }
468 }
469 else
470 {
471 rb_ssl_connect_realcb(F, RB_OK, sconn);
472 }
473 }
474
475 void
476 rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest,
477 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
478 {
479 struct ssl_connect *sconn;
480 if(F == NULL)
481 return;
482
483 sconn = rb_malloc(sizeof(struct ssl_connect));
484 sconn->data = data;
485 sconn->callback = callback;
486 sconn->timeout = timeout;
487 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
488
489 }
490
491 void
492 rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout)
493 {
494 struct ssl_connect *sconn;
495 int ssl_err;
496 if(F == NULL)
497 return;
498
499 sconn = rb_malloc(sizeof(struct ssl_connect));
500 sconn->data = data;
501 sconn->callback = callback;
502 sconn->timeout = timeout;
503 F->connect = rb_malloc(sizeof(struct conndata));
504 F->connect->callback = callback;
505 F->connect->data = data;
506 F->type |= RB_FD_SSL;
507 F->ssl = SSL_new(ssl_client_ctx);
508
509 SSL_set_fd((SSL *) F->ssl, F->fd);
510 rb_setup_ssl_cb(F);
511 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
512 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
513 {
514 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
515 {
516 case SSL_ERROR_SYSCALL:
517 if(rb_ignore_errno(errno))
518 case SSL_ERROR_WANT_READ:
519 case SSL_ERROR_WANT_WRITE:
520 {
521 F->ssl_errno = get_last_err();
522 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
523 rb_ssl_tryconn_cb, sconn);
524 return;
525 }
526 default:
527 F->ssl_errno = get_last_err();
528 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
529 return;
530 }
531 }
532 else
533 {
534 rb_ssl_connect_realcb(F, RB_OK, sconn);
535 }
536 }
537
538 int
539 rb_init_prng(const char *path, prng_seed_t seed_type)
540 {
541 if(seed_type == RB_PRNG_DEFAULT)
542 {
543 #ifdef WIN32
544 RAND_screen();
545 #endif
546 return RAND_status();
547 }
548 if(path == NULL)
549 return RAND_status();
550
551 switch (seed_type)
552 {
553 case RB_PRNG_EGD:
554 if(RAND_egd(path) == -1)
555 return -1;
556 break;
557 case RB_PRNG_FILE:
558 if(RAND_load_file(path, -1) == -1)
559 return -1;
560 break;
561 #ifdef WIN32
562 case RB_PRNGWIN32:
563 RAND_screen();
564 break;
565 #endif
566 default:
567 return -1;
568 }
569
570 return RAND_status();
571 }
572
573 int
574 rb_get_random(void *buf, size_t length)
575 {
576 int ret;
577
578 if((ret = RAND_bytes(buf, length)) == 0)
579 {
580 /* remove the error from the queue */
581 ERR_get_error();
582 }
583 return ret;
584 }
585
586 int
587 rb_get_pseudo_random(void *buf, size_t length)
588 {
589 int ret;
590 ret = RAND_pseudo_bytes(buf, length);
591 if(ret < 0)
592 return 0;
593 return 1;
594 }
595
596 const char *
597 rb_get_ssl_strerror(rb_fde_t * F)
598 {
599 return ERR_error_string(F->ssl_errno, NULL);
600 }
601
602 int
603 rb_supports_ssl(void)
604 {
605 return 1;
606 }
607
608 #endif /* HAVE_OPESSL */