2 * libratbox: a library used by ircd-ratbox and other things
3 * openssl.c: openssl related code
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
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.
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.
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
23 * $Id: commio.c 24808 2008-01-02 08:17:05Z androsyn $
26 #include <libratbox_config.h>
27 #include <ratbox_lib.h>
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>
38 static SSL_CTX
*ssl_server_ctx
;
39 static SSL_CTX
*ssl_client_ctx
;
41 static unsigned long get_last_err(void)
43 unsigned long t_err
, err
= 0;
44 err
= ERR_get_error();
48 while((t_err
= ERR_get_error()) > 0)
55 rb_ssl_shutdown(rb_fde_t
* F
)
58 if(F
== NULL
|| F
->ssl
== NULL
)
60 SSL_set_shutdown((SSL
*) F
->ssl
, SSL_RECEIVED_SHUTDOWN
);
62 for (i
= 0; i
< 4; i
++)
64 if(SSL_shutdown((SSL
*) F
->ssl
))
68 SSL_free((SSL
*) F
->ssl
);
72 rb_ssl_timeout(rb_fde_t
* F
, void *notused
)
74 lrb_assert(F
->accept
!= NULL
);
75 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
80 rb_ssl_tryaccept(rb_fde_t
* F
, void *data
)
83 lrb_assert(F
->accept
!= NULL
);
86 if(!SSL_is_init_finished((SSL
*) F
->ssl
))
88 if((ssl_err
= SSL_accept((SSL
*) F
->ssl
)) <= 0)
90 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
92 case SSL_ERROR_WANT_READ
:
93 case SSL_ERROR_WANT_WRITE
:
94 if(ssl_err
== SSL_ERROR_WANT_WRITE
)
95 flags
= RB_SELECT_WRITE
;
97 flags
= RB_SELECT_READ
;
98 F
->ssl_errno
= get_last_err();
99 rb_setselect(F
, flags
, rb_ssl_tryaccept
, NULL
);
101 case SSL_ERROR_SYSCALL
:
102 F
->accept
->callback(F
, RB_ERROR
, NULL
, 0, F
->accept
->data
);
105 F
->ssl_errno
= get_last_err();
106 F
->accept
->callback(F
, RB_ERROR_SSL
, NULL
, 0, F
->accept
->data
);
112 rb_settimeout(F
, 0, NULL
, NULL
);
113 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
115 F
->accept
->callback(F
, RB_OK
, (struct sockaddr
*) &F
->accept
->S
, F
->accept
->addrlen
,
123 rb_ssl_start_accepted(rb_fde_t
* new_F
, ACCB
* cb
, void *data
, int timeout
)
127 new_F
->type
|= RB_FD_SSL
;
128 new_F
->ssl
= SSL_new(ssl_server_ctx
);
129 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
131 new_F
->accept
->callback
= cb
;
132 new_F
->accept
->data
= data
;
133 rb_settimeout(new_F
, timeout
, rb_ssl_timeout
, NULL
);
135 new_F
->accept
->addrlen
= 0;
136 SSL_set_fd((SSL
*) new_F
->ssl
, rb_get_fd(new_F
));
137 if((ssl_err
= SSL_accept((SSL
*) new_F
->ssl
)) <= 0)
139 switch (ssl_err
= SSL_get_error((SSL
*) new_F
->ssl
, ssl_err
))
141 case SSL_ERROR_SYSCALL
:
142 if(rb_ignore_errno(errno
))
143 case SSL_ERROR_WANT_READ
:
144 case SSL_ERROR_WANT_WRITE
:
146 new_F
->ssl_errno
= get_last_err();
147 rb_setselect(new_F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
148 rb_ssl_tryaccept
, NULL
);
152 new_F
->ssl_errno
= get_last_err();
153 new_F
->accept
->callback(new_F
, RB_ERROR_SSL
, NULL
, 0, new_F
->accept
->data
);
159 rb_ssl_tryaccept(new_F
, NULL
);
167 rb_ssl_accept_setup(rb_fde_t
* F
, int new_fd
, struct sockaddr
*st
, int addrlen
)
172 new_F
= rb_find_fd(new_fd
);
173 new_F
->type
|= RB_FD_SSL
;
174 new_F
->ssl
= SSL_new(ssl_server_ctx
);
175 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
177 new_F
->accept
->callback
= F
->accept
->callback
;
178 new_F
->accept
->data
= F
->accept
->data
;
179 rb_settimeout(new_F
, 10, rb_ssl_timeout
, NULL
);
180 memcpy(&new_F
->accept
->S
, st
, addrlen
);
181 new_F
->accept
->addrlen
= addrlen
;
183 SSL_set_fd((SSL
*) new_F
->ssl
, new_fd
);
184 if((ssl_err
= SSL_accept((SSL
*) new_F
->ssl
)) <= 0)
186 switch (ssl_err
= SSL_get_error((SSL
*) new_F
->ssl
, ssl_err
))
188 case SSL_ERROR_SYSCALL
:
189 if(rb_ignore_errno(errno
))
190 case SSL_ERROR_WANT_READ
:
191 case SSL_ERROR_WANT_WRITE
:
193 F
->ssl_errno
= get_last_err();
194 rb_setselect(new_F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
195 rb_ssl_tryaccept
, NULL
);
199 F
->ssl_errno
= get_last_err();
200 F
->accept
->callback(F
, RB_ERROR_SSL
, NULL
, 0, F
->accept
->data
);
206 rb_ssl_tryaccept(new_F
, NULL
);
211 rb_ssl_read_or_write(int r_or_w
, rb_fde_t
* F
, void *rbuf
, const void *wbuf
, size_t count
)
218 ret
= (ssize_t
)SSL_read(ssl
, rbuf
, (int) count
);
220 ret
= (ssize_t
)SSL_write(ssl
, wbuf
, (int) count
);
224 switch (SSL_get_error(ssl
, ret
))
226 case SSL_ERROR_WANT_READ
:
228 return RB_RW_SSL_NEED_READ
;
229 case SSL_ERROR_WANT_WRITE
:
231 return RB_RW_SSL_NEED_WRITE
;
232 case SSL_ERROR_ZERO_RETURN
:
234 case SSL_ERROR_SYSCALL
:
235 err
= get_last_err();
239 return RB_RW_IO_ERROR
;
243 err
= get_last_err();
249 errno
= EIO
; /* not great but... */
250 return RB_RW_SSL_ERROR
;
252 return RB_RW_IO_ERROR
;
258 rb_ssl_read(rb_fde_t
* F
, void *buf
, size_t count
)
260 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
264 rb_ssl_write(rb_fde_t
* F
, const void *buf
, size_t count
)
266 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
273 SSL_load_error_strings();
275 ssl_server_ctx
= SSL_CTX_new(SSLv23_server_method());
276 if(ssl_server_ctx
== NULL
)
278 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
279 ERR_error_string(ERR_get_error(), NULL
));
282 /* Disable SSLv2, make the client use our settings */
283 SSL_CTX_set_options(ssl_server_ctx
, SSL_OP_NO_SSLv2
| SSL_OP_CIPHER_SERVER_PREFERENCE
);
285 ssl_client_ctx
= SSL_CTX_new(TLSv1_client_method());
287 if(ssl_client_ctx
== NULL
)
289 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
290 ERR_error_string(ERR_get_error(), NULL
));
298 rb_setup_ssl_server(const char *cert
, const char *keyfile
, const char *dhfile
)
305 rb_lib_log("rb_setup_ssl_server: No certificate file");
308 if(!SSL_CTX_use_certificate_file(ssl_server_ctx
, cert
, SSL_FILETYPE_PEM
))
310 err
= ERR_get_error();
311 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert
,
312 ERR_error_string(err
, NULL
));
318 rb_lib_log("rb_setup_ssl_server: No key file");
323 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx
, keyfile
, SSL_FILETYPE_PEM
))
325 err
= ERR_get_error();
326 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile
,
327 ERR_error_string(err
, NULL
));
333 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
334 param
= fopen(dhfile
, "r");
337 dh
= PEM_read_DHparams(param
, NULL
, NULL
, NULL
);
340 err
= ERR_get_error();
342 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
343 param
, ERR_error_string(err
, NULL
));
347 SSL_CTX_set_tmp_dh(ssl_server_ctx
, dh
);
355 rb_ssl_listen(rb_fde_t
* F
, int backlog
)
357 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
358 return listen(F
->fd
, backlog
);
369 rb_ssl_connect_realcb(rb_fde_t
* F
, int status
, struct ssl_connect
*sconn
)
371 F
->connect
->callback
= sconn
->callback
;
372 F
->connect
->data
= sconn
->data
;
374 rb_connect_callback(F
, status
);
378 rb_ssl_tryconn_timeout_cb(rb_fde_t
* F
, void *data
)
380 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
384 rb_ssl_tryconn_cb(rb_fde_t
* F
, void *data
)
386 struct ssl_connect
*sconn
= data
;
388 if(!SSL_is_init_finished((SSL
*) F
->ssl
))
390 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
392 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
394 case SSL_ERROR_SYSCALL
:
395 if(rb_ignore_errno(errno
))
396 case SSL_ERROR_WANT_READ
:
397 case SSL_ERROR_WANT_WRITE
:
399 F
->ssl_errno
= get_last_err();
400 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
401 rb_ssl_tryconn_cb
, sconn
);
405 F
->ssl_errno
= get_last_err();
406 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
412 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
418 rb_ssl_tryconn(rb_fde_t
* F
, int status
, void *data
)
420 struct ssl_connect
*sconn
= data
;
424 rb_ssl_connect_realcb(F
, status
, sconn
);
428 F
->type
|= RB_FD_SSL
;
429 F
->ssl
= SSL_new(ssl_client_ctx
);
430 SSL_set_fd((SSL
*) F
->ssl
, F
->fd
);
432 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
433 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
435 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
437 case SSL_ERROR_SYSCALL
:
438 if(rb_ignore_errno(errno
))
439 case SSL_ERROR_WANT_READ
:
440 case SSL_ERROR_WANT_WRITE
:
442 F
->ssl_errno
= get_last_err();
443 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
444 rb_ssl_tryconn_cb
, sconn
);
448 F
->ssl_errno
= get_last_err();
449 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
455 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
460 rb_connect_tcp_ssl(rb_fde_t
* F
, struct sockaddr
*dest
,
461 struct sockaddr
*clocal
, int socklen
, CNCB
* callback
, void *data
, int timeout
)
463 struct ssl_connect
*sconn
;
467 sconn
= rb_malloc(sizeof(struct ssl_connect
));
469 sconn
->callback
= callback
;
470 sconn
->timeout
= timeout
;
471 rb_connect_tcp(F
, dest
, clocal
, socklen
, rb_ssl_tryconn
, sconn
, timeout
);
476 rb_ssl_start_connected(rb_fde_t
* F
, CNCB
* callback
, void *data
, int timeout
)
478 struct ssl_connect
*sconn
;
483 sconn
= rb_malloc(sizeof(struct ssl_connect
));
485 sconn
->callback
= callback
;
486 sconn
->timeout
= timeout
;
487 F
->connect
= rb_malloc(sizeof(struct conndata
));
488 F
->connect
->callback
= callback
;
489 F
->connect
->data
= data
;
490 F
->type
|= RB_FD_SSL
;
491 F
->ssl
= SSL_new(ssl_client_ctx
);
493 SSL_set_fd((SSL
*) F
->ssl
, F
->fd
);
494 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
495 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
497 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
499 case SSL_ERROR_SYSCALL
:
500 if(rb_ignore_errno(errno
))
501 case SSL_ERROR_WANT_READ
:
502 case SSL_ERROR_WANT_WRITE
:
504 F
->ssl_errno
= get_last_err();
505 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
506 rb_ssl_tryconn_cb
, sconn
);
510 F
->ssl_errno
= get_last_err();
511 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
517 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
522 rb_init_prng(const char *path
, prng_seed_t seed_type
)
524 if(seed_type
== RB_PRNG_DEFAULT
)
529 return RAND_status();
532 return RAND_status();
537 if(RAND_egd(path
) == -1)
541 if(RAND_load_file(path
, -1) == -1)
553 return RAND_status();
557 rb_get_random(void *buf
, size_t length
)
561 if(RAND_bytes(buf
, length
) > 0)
566 if(RAND_pseudo_bytes(buf
, length
) >= 0)
574 rb_get_ssl_strerror(rb_fde_t
* F
)
576 return ERR_error_string(F
->ssl_errno
, NULL
);
580 rb_supports_ssl(void)
585 #endif /* HAVE_OPESSL */