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
25 #include <libratbox_config.h>
26 #include <ratbox_lib.h>
30 #include <commio-int.h>
31 #include <commio-ssl.h>
32 #include <openssl/ssl.h>
33 #include <openssl/dh.h>
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
37 static SSL_CTX
*ssl_server_ctx
;
38 static SSL_CTX
*ssl_client_ctx
;
39 static int libratbox_index
= -1;
44 unsigned long t_err
, err
= 0;
45 err
= ERR_get_error();
49 while((t_err
= ERR_get_error()) > 0)
56 rb_ssl_shutdown(rb_fde_t
*F
)
59 if(F
== NULL
|| F
->ssl
== NULL
)
61 SSL_set_shutdown((SSL
*) F
->ssl
, SSL_RECEIVED_SHUTDOWN
);
63 for(i
= 0; i
< 4; i
++)
65 if(SSL_shutdown((SSL
*) F
->ssl
))
69 SSL_free((SSL
*) F
->ssl
);
73 rb_ssl_handshake_count(rb_fde_t
*F
)
75 return F
->handshake_count
;
79 rb_ssl_clear_handshake_count(rb_fde_t
*F
)
81 F
->handshake_count
= 0;
85 rb_ssl_timeout(rb_fde_t
*F
, void *notused
)
87 lrb_assert(F
->accept
!= NULL
);
88 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
93 rb_ssl_info_callback(SSL
* ssl
, int where
, int ret
)
95 if(where
& SSL_CB_HANDSHAKE_START
)
97 rb_fde_t
*F
= SSL_get_ex_data(ssl
, libratbox_index
);
100 F
->handshake_count
++;
105 rb_setup_ssl_cb(rb_fde_t
*F
)
107 SSL_set_ex_data(F
->ssl
, libratbox_index
, (char *)F
);
108 SSL_set_info_callback((SSL
*) F
->ssl
, (void (*)(const SSL
*,int,int))rb_ssl_info_callback
);
112 rb_ssl_tryaccept(rb_fde_t
*F
, void *data
)
115 lrb_assert(F
->accept
!= NULL
);
117 struct acceptdata
*ad
;
119 if(!SSL_is_init_finished((SSL
*) F
->ssl
))
121 if((ssl_err
= SSL_accept((SSL
*) F
->ssl
)) <= 0)
123 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
125 case SSL_ERROR_WANT_READ
:
126 case SSL_ERROR_WANT_WRITE
:
127 if(ssl_err
== SSL_ERROR_WANT_WRITE
)
128 flags
= RB_SELECT_WRITE
;
130 flags
= RB_SELECT_READ
;
131 F
->ssl_errno
= get_last_err();
132 rb_setselect(F
, flags
, rb_ssl_tryaccept
, NULL
);
134 case SSL_ERROR_SYSCALL
:
135 F
->accept
->callback(F
, RB_ERROR
, NULL
, 0, F
->accept
->data
);
138 F
->ssl_errno
= get_last_err();
139 F
->accept
->callback(F
, RB_ERROR_SSL
, NULL
, 0, F
->accept
->data
);
145 rb_settimeout(F
, 0, NULL
, NULL
);
146 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
150 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
157 rb_ssl_accept_common(rb_fde_t
*new_F
)
160 if((ssl_err
= SSL_accept((SSL
*) new_F
->ssl
)) <= 0)
162 switch (ssl_err
= SSL_get_error((SSL
*) new_F
->ssl
, ssl_err
))
164 case SSL_ERROR_SYSCALL
:
165 if(rb_ignore_errno(errno
))
166 case SSL_ERROR_WANT_READ
:
167 case SSL_ERROR_WANT_WRITE
:
169 new_F
->ssl_errno
= get_last_err();
170 rb_setselect(new_F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
171 rb_ssl_tryaccept
, NULL
);
175 new_F
->ssl_errno
= get_last_err();
176 new_F
->accept
->callback(new_F
, RB_ERROR_SSL
, NULL
, 0, new_F
->accept
->data
);
182 rb_ssl_tryaccept(new_F
, NULL
);
187 rb_ssl_start_accepted(rb_fde_t
*new_F
, ACCB
* cb
, void *data
, int timeout
)
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
));
193 new_F
->accept
->callback
= cb
;
194 new_F
->accept
->data
= data
;
195 rb_settimeout(new_F
, timeout
, rb_ssl_timeout
, NULL
);
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
);
207 rb_ssl_accept_setup(rb_fde_t
*F
, rb_fde_t
*new_F
, struct sockaddr
*st
, int addrlen
)
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
));
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
;
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
);
225 rb_ssl_read_or_write(int r_or_w
, rb_fde_t
*F
, void *rbuf
, const void *wbuf
, size_t count
)
232 ret
= (ssize_t
) SSL_read(ssl
, rbuf
, (int)count
);
234 ret
= (ssize_t
) SSL_write(ssl
, wbuf
, (int)count
);
238 switch (SSL_get_error(ssl
, ret
))
240 case SSL_ERROR_WANT_READ
:
242 return RB_RW_SSL_NEED_READ
;
243 case SSL_ERROR_WANT_WRITE
:
245 return RB_RW_SSL_NEED_WRITE
;
246 case SSL_ERROR_ZERO_RETURN
:
248 case SSL_ERROR_SYSCALL
:
249 err
= get_last_err();
253 return RB_RW_IO_ERROR
;
257 err
= get_last_err();
263 errno
= EIO
; /* not great but... */
264 return RB_RW_SSL_ERROR
;
266 return RB_RW_IO_ERROR
;
272 rb_ssl_read(rb_fde_t
*F
, void *buf
, size_t count
)
274 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
278 rb_ssl_write(rb_fde_t
*F
, const void *buf
, size_t count
)
280 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
284 verify_accept_all_cb(int preverify_ok
, X509_STORE_CTX
*x509_ctx
)
290 get_ssl_error(unsigned long err
)
292 static char buf
[512];
294 ERR_error_string_n(err
, buf
, sizeof buf
);
302 char libratbox_data
[] = "libratbox data";
303 SSL_load_error_strings();
305 libratbox_index
= SSL_get_ex_new_index(0, libratbox_data
, NULL
, NULL
, NULL
);
306 ssl_server_ctx
= SSL_CTX_new(SSLv23_server_method());
307 if(ssl_server_ctx
== NULL
)
309 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
310 get_ssl_error(ERR_get_error()));
313 /* Disable SSLv2, make the client use our settings */
314 SSL_CTX_set_options(ssl_server_ctx
, SSL_OP_NO_SSLv2
| SSL_OP_CIPHER_SERVER_PREFERENCE
);
315 SSL_CTX_set_verify(ssl_server_ctx
, SSL_VERIFY_PEER
| SSL_VERIFY_CLIENT_ONCE
, verify_accept_all_cb
);
317 ssl_client_ctx
= SSL_CTX_new(TLSv1_client_method());
319 if(ssl_client_ctx
== NULL
)
321 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
322 get_ssl_error(ERR_get_error()));
330 rb_setup_ssl_server(const char *cert
, const char *keyfile
, const char *dhfile
)
336 rb_lib_log("rb_setup_ssl_server: No certificate file");
339 if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx
, cert
) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx
, cert
))
341 err
= ERR_get_error();
342 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert
,
349 rb_lib_log("rb_setup_ssl_server: No key file");
354 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx
, keyfile
, SSL_FILETYPE_PEM
) || !SSL_CTX_use_PrivateKey_file(ssl_client_ctx
, keyfile
, SSL_FILETYPE_PEM
))
356 err
= ERR_get_error();
357 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile
,
364 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
365 BIO
*bio
= BIO_new_file(dhfile
, "r");
368 dh
= PEM_read_bio_DHparams(bio
, NULL
, NULL
, NULL
);
371 err
= ERR_get_error();
373 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
374 dhfile
, get_ssl_error(err
));
379 SSL_CTX_set_tmp_dh(ssl_server_ctx
, dh
);
383 err
= ERR_get_error();
384 rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
385 dhfile
, get_ssl_error(err
));
392 rb_ssl_listen(rb_fde_t
*F
, int backlog
)
394 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
395 return listen(F
->fd
, backlog
);
406 rb_ssl_connect_realcb(rb_fde_t
*F
, int status
, struct ssl_connect
*sconn
)
408 F
->connect
->callback
= sconn
->callback
;
409 F
->connect
->data
= sconn
->data
;
411 rb_connect_callback(F
, status
);
415 rb_ssl_tryconn_timeout_cb(rb_fde_t
*F
, void *data
)
417 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
421 rb_ssl_tryconn_cb(rb_fde_t
*F
, void *data
)
423 struct ssl_connect
*sconn
= data
;
425 if(!SSL_is_init_finished((SSL
*) F
->ssl
))
427 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
429 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
431 case SSL_ERROR_SYSCALL
:
432 if(rb_ignore_errno(errno
))
433 case SSL_ERROR_WANT_READ
:
434 case SSL_ERROR_WANT_WRITE
:
436 F
->ssl_errno
= get_last_err();
437 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
438 rb_ssl_tryconn_cb
, sconn
);
442 F
->ssl_errno
= get_last_err();
443 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
449 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
455 rb_ssl_tryconn(rb_fde_t
*F
, int status
, void *data
)
457 struct ssl_connect
*sconn
= data
;
461 rb_ssl_connect_realcb(F
, status
, sconn
);
465 F
->type
|= RB_FD_SSL
;
466 F
->ssl
= SSL_new(ssl_client_ctx
);
467 SSL_set_fd((SSL
*) F
->ssl
, F
->fd
);
469 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
470 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
472 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
474 case SSL_ERROR_SYSCALL
:
475 if(rb_ignore_errno(errno
))
476 case SSL_ERROR_WANT_READ
:
477 case SSL_ERROR_WANT_WRITE
:
479 F
->ssl_errno
= get_last_err();
480 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
481 rb_ssl_tryconn_cb
, sconn
);
485 F
->ssl_errno
= get_last_err();
486 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
492 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
497 rb_connect_tcp_ssl(rb_fde_t
*F
, struct sockaddr
*dest
,
498 struct sockaddr
*clocal
, int socklen
, CNCB
* callback
, void *data
, int timeout
)
500 struct ssl_connect
*sconn
;
504 sconn
= rb_malloc(sizeof(struct ssl_connect
));
506 sconn
->callback
= callback
;
507 sconn
->timeout
= timeout
;
508 rb_connect_tcp(F
, dest
, clocal
, socklen
, rb_ssl_tryconn
, sconn
, timeout
);
513 rb_ssl_start_connected(rb_fde_t
*F
, CNCB
* callback
, void *data
, int timeout
)
515 struct ssl_connect
*sconn
;
520 sconn
= rb_malloc(sizeof(struct ssl_connect
));
522 sconn
->callback
= callback
;
523 sconn
->timeout
= timeout
;
524 F
->connect
= rb_malloc(sizeof(struct conndata
));
525 F
->connect
->callback
= callback
;
526 F
->connect
->data
= data
;
527 F
->type
|= RB_FD_SSL
;
528 F
->ssl
= SSL_new(ssl_client_ctx
);
530 SSL_set_fd((SSL
*) F
->ssl
, F
->fd
);
532 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
533 if((ssl_err
= SSL_connect((SSL
*) F
->ssl
)) <= 0)
535 switch (ssl_err
= SSL_get_error((SSL
*) F
->ssl
, ssl_err
))
537 case SSL_ERROR_SYSCALL
:
538 if(rb_ignore_errno(errno
))
539 case SSL_ERROR_WANT_READ
:
540 case SSL_ERROR_WANT_WRITE
:
542 F
->ssl_errno
= get_last_err();
543 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
,
544 rb_ssl_tryconn_cb
, sconn
);
548 F
->ssl_errno
= get_last_err();
549 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
555 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
560 rb_init_prng(const char *path
, prng_seed_t seed_type
)
562 if(seed_type
== RB_PRNG_DEFAULT
)
567 return RAND_status();
570 return RAND_status();
575 if(RAND_egd(path
) == -1)
579 if(RAND_load_file(path
, -1) == -1)
591 return RAND_status();
595 rb_get_random(void *buf
, size_t length
)
599 if((ret
= RAND_bytes(buf
, length
)) == 0)
601 /* remove the error from the queue */
608 rb_get_pseudo_random(void *buf
, size_t length
)
611 ret
= RAND_pseudo_bytes(buf
, length
);
618 rb_get_ssl_strerror(rb_fde_t
*F
)
620 return get_ssl_error(F
->ssl_errno
);
624 rb_get_ssl_certfp(rb_fde_t
*F
, uint8_t certfp
[RB_SSL_CERTFP_LEN
])
632 cert
= SSL_get_peer_certificate((SSL
*) F
->ssl
);
635 res
= SSL_get_verify_result((SSL
*) F
->ssl
);
636 if(res
== X509_V_OK
||
637 res
== X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
||
638 res
== X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
||
639 res
== X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
)
641 memcpy(certfp
, cert
->sha1_hash
, RB_SSL_CERTFP_LEN
);
651 rb_supports_ssl(void)
657 rb_get_ssl_info(char *buf
, size_t len
)
659 rb_snprintf(buf
, len
, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
660 SSLeay_version(SSLEAY_VERSION
),
661 (long)OPENSSL_VERSION_NUMBER
, SSLeay());
665 #endif /* HAVE_OPESSL */