X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/b68b0b2cde283af05ca0169ad950b6e8e270d227..84bfb8ccb31b3ea5a083d0f51b249bba7e62a0b0:/libratbox/src/openssl.c diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index 24f4ea0..9a76063 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -37,14 +37,16 @@ static SSL_CTX *ssl_server_ctx; static SSL_CTX *ssl_client_ctx; +static int libratbox_index = -1; -static unsigned long get_last_err(void) +static unsigned long +get_last_err(void) { unsigned long t_err, err = 0; err = ERR_get_error(); if(err == 0) return 0; - + while((t_err = ERR_get_error()) > 0) err = t_err; @@ -52,14 +54,14 @@ static unsigned long get_last_err(void) } void -rb_ssl_shutdown(rb_fde_t * F) +rb_ssl_shutdown(rb_fde_t *F) { int i; if(F == NULL || F->ssl == NULL) return; SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN); - for (i = 0; i < 4; i++) + for(i = 0; i < 4; i++) { if(SSL_shutdown((SSL *) F->ssl)) break; @@ -68,8 +70,20 @@ rb_ssl_shutdown(rb_fde_t * F) SSL_free((SSL *) F->ssl); } +unsigned int +rb_ssl_handshake_count(rb_fde_t *F) +{ + return F->handshake_count; +} + +void +rb_ssl_clear_handshake_count(rb_fde_t *F) +{ + F->handshake_count = 0; +} + static void -rb_ssl_timeout(rb_fde_t * F, void *notused) +rb_ssl_timeout(rb_fde_t *F, void *notused) { lrb_assert(F->accept != NULL); F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); @@ -77,7 +91,26 @@ rb_ssl_timeout(rb_fde_t * F, void *notused) static void -rb_ssl_tryaccept(rb_fde_t * F, void *data) +rb_ssl_info_callback(SSL * ssl, int where, int ret) +{ + if(where & SSL_CB_HANDSHAKE_START) + { + rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index); + if(F == NULL) + return; + F->handshake_count++; + } +} + +static void +rb_setup_ssl_cb(rb_fde_t *F) +{ + SSL_set_ex_data(F->ssl, libratbox_index, (char *)F); + SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *,int,int))rb_ssl_info_callback); +} + +static void +rb_ssl_tryaccept(rb_fde_t *F, void *data) { int ssl_err; lrb_assert(F->accept != NULL); @@ -112,30 +145,19 @@ rb_ssl_tryaccept(rb_fde_t * F, void *data) } rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); - + ad = F->accept; F->accept = NULL; - ad->callback(F, RB_OK, (struct sockaddr *) &ad->S, ad->addrlen, - ad->data); + ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); } -void -rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout) + +static void +rb_ssl_accept_common(rb_fde_t *new_F) { int ssl_err; - - new_F->type |= RB_FD_SSL; - new_F->ssl = SSL_new(ssl_server_ctx); - new_F->accept = rb_malloc(sizeof(struct acceptdata)); - - new_F->accept->callback = cb; - new_F->accept->data = data; - rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); - - new_F->accept->addrlen = 0; - SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0) { switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err)) @@ -162,16 +184,29 @@ rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout) } } +void +rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) +{ + new_F->type |= RB_FD_SSL; + new_F->ssl = SSL_new(ssl_server_ctx); + new_F->accept = rb_malloc(sizeof(struct acceptdata)); + + new_F->accept->callback = cb; + new_F->accept->data = data; + rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); + + new_F->accept->addrlen = 0; + SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); + rb_setup_ssl_cb(new_F); + rb_ssl_accept_common(new_F); +} + void -rb_ssl_accept_setup(rb_fde_t * F, int new_fd, struct sockaddr *st, int addrlen) +rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen) { - rb_fde_t *new_F; - int ssl_err; - - new_F = rb_find_fd(new_fd); new_F->type |= RB_FD_SSL; new_F->ssl = SSL_new(ssl_server_ctx); new_F->accept = rb_malloc(sizeof(struct acceptdata)); @@ -182,44 +217,22 @@ rb_ssl_accept_setup(rb_fde_t * F, int new_fd, struct sockaddr *st, int addrlen) memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; - SSL_set_fd((SSL *) new_F->ssl, new_fd); - if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0) - { - switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err)) - { - case SSL_ERROR_SYSCALL: - if(rb_ignore_errno(errno)) - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - { - F->ssl_errno = get_last_err(); - rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE, - rb_ssl_tryaccept, NULL); - return; - } - default: - F->ssl_errno = get_last_err(); - F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data); - return; - } - } - else - { - rb_ssl_tryaccept(new_F, NULL); - } + SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); + rb_setup_ssl_cb(new_F); + rb_ssl_accept_common(new_F); } static ssize_t -rb_ssl_read_or_write(int r_or_w, rb_fde_t * F, void *rbuf, const void *wbuf, size_t count) +rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) { ssize_t ret; unsigned long err; SSL *ssl = F->ssl; if(r_or_w == 0) - ret = (ssize_t)SSL_read(ssl, rbuf, (int) count); + ret = (ssize_t) SSL_read(ssl, rbuf, (int)count); else - ret = (ssize_t)SSL_write(ssl, wbuf, (int) count); + ret = (ssize_t) SSL_write(ssl, wbuf, (int)count); if(ret < 0) { @@ -257,13 +270,13 @@ rb_ssl_read_or_write(int r_or_w, rb_fde_t * F, void *rbuf, const void *wbuf, siz } ssize_t -rb_ssl_read(rb_fde_t * F, void *buf, size_t count) +rb_ssl_read(rb_fde_t *F, void *buf, size_t count) { return rb_ssl_read_or_write(0, F, buf, NULL, count); } ssize_t -rb_ssl_write(rb_fde_t * F, const void *buf, size_t count) +rb_ssl_write(rb_fde_t *F, const void *buf, size_t count) { return rb_ssl_read_or_write(1, F, NULL, buf, count); } @@ -272,8 +285,10 @@ int rb_init_ssl(void) { int ret = 1; + char libratbox_data[] = "libratbox data"; SSL_load_error_strings(); SSL_library_init(); + libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL); ssl_server_ctx = SSL_CTX_new(SSLv23_server_method()); if(ssl_server_ctx == NULL) { @@ -283,7 +298,7 @@ rb_init_ssl(void) } /* Disable SSLv2, make the client use our settings */ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE); - + ssl_client_ctx = SSL_CTX_new(TLSv1_client_method()); if(ssl_client_ctx == NULL) @@ -299,7 +314,6 @@ rb_init_ssl(void) int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) { - FILE *param; DH *dh; unsigned long err; if(cert == NULL) @@ -333,28 +347,34 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) if(dhfile != NULL) { /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */ - param = fopen(dhfile, "r"); - if(param != NULL) + BIO *bio = BIO_new_file(dhfile, "r"); + if(bio != NULL) { - dh = PEM_read_DHparams(param, NULL, NULL, NULL); + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); if(dh == NULL) { err = ERR_get_error(); rb_lib_log ("rb_setup_ssl_server: Error loading DH params file [%s]: %s", - param, ERR_error_string(err, NULL)); - fclose(param); + dhfile, ERR_error_string(err, NULL)); + BIO_free(bio); return 0; } + BIO_free(bio); SSL_CTX_set_tmp_dh(ssl_server_ctx, dh); - fclose(param); + } + else + { + err = ERR_get_error(); + rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s", + dhfile, ERR_error_string(err, NULL)); } } return 1; } int -rb_ssl_listen(rb_fde_t * F, int backlog) +rb_ssl_listen(rb_fde_t *F, int backlog) { F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; return listen(F->fd, backlog); @@ -368,7 +388,7 @@ struct ssl_connect }; static void -rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn) +rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn) { F->connect->callback = sconn->callback; F->connect->data = sconn->data; @@ -377,13 +397,13 @@ rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn) } static void -rb_ssl_tryconn_timeout_cb(rb_fde_t * F, void *data) +rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data) { rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); } static void -rb_ssl_tryconn_cb(rb_fde_t * F, void *data) +rb_ssl_tryconn_cb(rb_fde_t *F, void *data) { struct ssl_connect *sconn = data; int ssl_err; @@ -417,7 +437,7 @@ rb_ssl_tryconn_cb(rb_fde_t * F, void *data) } static void -rb_ssl_tryconn(rb_fde_t * F, int status, void *data) +rb_ssl_tryconn(rb_fde_t *F, int status, void *data) { struct ssl_connect *sconn = data; int ssl_err; @@ -430,7 +450,7 @@ rb_ssl_tryconn(rb_fde_t * F, int status, void *data) F->type |= RB_FD_SSL; F->ssl = SSL_new(ssl_client_ctx); SSL_set_fd((SSL *) F->ssl, F->fd); - + rb_setup_ssl_cb(F); rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0) { @@ -459,7 +479,7 @@ rb_ssl_tryconn(rb_fde_t * F, int status, void *data) } void -rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest, +rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest, struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout) { struct ssl_connect *sconn; @@ -475,7 +495,7 @@ rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest, } void -rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout) +rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) { struct ssl_connect *sconn; int ssl_err; @@ -491,8 +511,9 @@ rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout) F->connect->data = data; F->type |= RB_FD_SSL; F->ssl = SSL_new(ssl_client_ctx); - + SSL_set_fd((SSL *) F->ssl, F->fd); + rb_setup_ssl_cb(F); rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0) { @@ -525,7 +546,7 @@ rb_init_prng(const char *path, prng_seed_t seed_type) { if(seed_type == RB_PRNG_DEFAULT) { -#ifdef WIN32 +#ifdef _WIN32 RAND_screen(); #endif return RAND_status(); @@ -543,7 +564,7 @@ rb_init_prng(const char *path, prng_seed_t seed_type) if(RAND_load_file(path, -1) == -1) return -1; break; -#ifdef WIN32 +#ifdef _WIN32 case RB_PRNGWIN32: RAND_screen(); break; @@ -558,22 +579,28 @@ rb_init_prng(const char *path, prng_seed_t seed_type) int rb_get_random(void *buf, size_t length) { - if(RAND_status()) - { - if(RAND_bytes(buf, length) > 0) - return 1; - } - else + int ret; + + if((ret = RAND_bytes(buf, length)) == 0) { - if(RAND_pseudo_bytes(buf, length) >= 0) - return 1; + /* remove the error from the queue */ + ERR_get_error(); } - return 0; + return ret; } +int +rb_get_pseudo_random(void *buf, size_t length) +{ + int ret; + ret = RAND_pseudo_bytes(buf, length); + if(ret < 0) + return 0; + return 1; +} const char * -rb_get_ssl_strerror(rb_fde_t * F) +rb_get_ssl_strerror(rb_fde_t *F) { return ERR_error_string(F->ssl_errno, NULL); }