static int rb_epoll_sched_event_timerfd(struct ev_entry *event, int when) { struct itimerspec ts; static char buf[FD_DESC_SZ + 8]; int fd; rb_fde_t *F; if((fd = timerfd_create(CLOCK_REALTIME, 0)) < 0) { rb_lib_log("timerfd_create: %s\n", strerror(errno)); return 0; } memset(&ts, 0, sizeof(ts)); ts.it_value.tv_sec = when; ts.it_value.tv_nsec = 0; if(event->frequency != 0) ts.it_interval = ts.it_value; if(timerfd_settime(fd, 0, &ts, NULL) < 0) { rb_lib_log("timerfd_settime: %s\n", strerror(errno)); close(fd); return 0; } rb_snprintf(buf, sizeof(buf), "timerfd: %s", event->name); F = rb_open(fd, RB_FD_UNKNOWN, buf); rb_set_nb(F); event->comm_ptr = F; rb_setselect(F, RB_SELECT_READ, rb_read_timerfd, event); return 1; }
static int rb_epoll_sched_event_signalfd(struct ev_entry *event, int when) { timer_t *id; struct sigevent ev; struct itimerspec ts; memset(&ev, 0, sizeof(ev)); event->comm_ptr = rb_malloc(sizeof(timer_t)); id = event->comm_ptr; ev.sigev_notify = SIGEV_SIGNAL; ev.sigev_signo = RTSIGNAL; ev.sigev_value.sival_ptr = event; if(timer_create(CLOCK_REALTIME, &ev, id) < 0) { rb_lib_log("timer_create: %s\n", strerror(errno)); return 0; } memset(&ts, 0, sizeof(ts)); ts.it_value.tv_sec = when; ts.it_value.tv_nsec = 0; if(event->frequency != 0) ts.it_interval = ts.it_value; if(timer_settime(*id, 0, &ts, NULL) < 0) { rb_lib_log("timer_settime: %s\n", strerror(errno)); return 0; } return 1; }
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) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", get_ssl_error(ERR_get_error())); ret = 0; } /* 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_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); ssl_client_ctx = SSL_CTX_new(TLSv1_client_method()); if(ssl_client_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s", get_ssl_error(ERR_get_error())); ret = 0; } return ret; }
rb_ssl_ctx * rb_setup_ssl_client(const char *ssl_cipher_list, const char *cert, const char *keyfile) { int ret; rb_ssl_ctx *sctx; sctx = rb_malloc(sizeof(rb_ssl_ctx)); mbedtls_ssl_config_init(&sctx->config); if ((ret = mbedtls_ssl_config_defaults(&sctx->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for client context: -0x%x", -ret); return 0; } mbedtls_ssl_conf_rng(&sctx->config, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_authmode(&sctx->config, MBEDTLS_SSL_VERIFY_NONE); if(cert != NULL && keyfile != NULL) { mbedtls_x509_crt_init(&sctx->x509); ret = mbedtls_x509_crt_parse_file(&sctx->x509, cert); if (ret != 0) { rb_lib_log("rb_setup_ssl_client: failed to parse certificate '%s': -0x%x", cert, -ret); return 0; } mbedtls_pk_init(&sctx->serv_pk); ret = mbedtls_pk_parse_keyfile(&sctx->serv_pk, keyfile, NULL); if (ret != 0) { rb_lib_log("rb_setup_ssl_client: failed to parse private key '%s': -0x%x", keyfile, -ret); return 0; } if (&sctx->x509.next) mbedtls_ssl_conf_ca_chain(&sctx->config, sctx->x509.next, NULL); if ((ret = mbedtls_ssl_conf_own_cert(&sctx->config, &sctx->x509, &sctx->serv_pk)) != 0) { rb_lib_log("rb_setup_ssl_client: failed to set up own certificate: -0x%x", -ret); return 0; } } return sctx; }
rb_ssl_ctx * rb_setup_ssl_client(const char *ssl_cipher_list, const char *cert, const char *keyfile) { /* this needs to have more customizations etc...client certificates perhaps as well */ rb_ssl_ctx *sctx; sctx = rb_malloc(sizeof(rb_ssl_ctx)); sctx->refcount = 1; sctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); SSL_CTX_set_options(sctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); if(sctx->ssl_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s", ERR_error_string(ERR_get_error(), NULL)); rb_free(sctx); return NULL; } if(ssl_cipher_list != NULL) { if(!SSL_CTX_set_cipher_list(sctx->ssl_ctx, ssl_cipher_list)) { rb_lib_log("rb_setup_ssl_client: Error setting ssl_cipher_list=\"%s\": %s", ssl_cipher_list, ERR_error_string(ERR_get_error(), NULL)); goto cleanup; } } if(cert != NULL && keyfile != NULL) { if(!SSL_CTX_use_PrivateKey_file(sctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM)) { rb_lib_log("rb_setup_ssl_client: Error loading keyfile :%s", ERR_error_string(ERR_get_error(), NULL)); goto cleanup; } if(!SSL_CTX_use_certificate_chain_file(sctx->ssl_ctx, cert)) { rb_lib_log("rb_setup_ssl_client: Error loading certificate :%s", ERR_error_string(ERR_get_error(), NULL)); goto cleanup; } } return sctx; cleanup: SSL_CTX_free(sctx->ssl_ctx); rb_free(sctx); return NULL; }
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) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", get_ssl_error(ERR_get_error())); ret = 0; } /* Disable SSLv2, make the client use our settings */ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE #ifdef SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_DH_USE #endif ); SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); SSL_CTX_set_session_id_context(ssl_server_ctx, (const unsigned char *)"libratbox", 9); SSL_CTX_set_cipher_list(ssl_server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL"); /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks and bastardise their OpenSSL for stupid reasons... */ #if (OPENSSL_VERSION_NUMBER >= 0x10000000) && defined(NID_secp384r1) EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1); if (key) { SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key); EC_KEY_free(key); } #ifdef SSL_OP_SINGLE_ECDH_USE SSL_CTX_set_options(ssl_server_ctx, SSL_OP_SINGLE_ECDH_USE); #endif #endif ssl_client_ctx = SSL_CTX_new(TLSv1_client_method()); if(ssl_client_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s", get_ssl_error(ERR_get_error())); ret = 0; } return ret; }
void rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, rb_socklen_t addrlen) { if(new_F->sctx == NULL) return; new_F->type |= RB_FD_SSL; new_F->ssl = SSL_new(new_F->sctx->ssl_ctx); if(new_F->ssl == NULL) { new_F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_accept_setup: SSL_new() fails: %s", ERR_error_string(new_F->sslerr.ssl_errno, NULL)); new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data); return; } new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = F->accept->callback; new_F->accept->data = F->accept->data; rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; 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_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) { if(new_F->sctx == NULL) return; new_F->type |= RB_FD_SSL; new_F->ssl = SSL_new(new_F->sctx->ssl_ctx); if(new_F->ssl == NULL) { new_F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_start_accepted: SSL_new() fails: %s", ERR_error_string(new_F->sslerr.ssl_errno, NULL)); cb(new_F, RB_ERROR_SSL, NULL, 0, data); return; } 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); }
int rb_ssl_get_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) { const mbedtls_x509_crt *peer_cert; uint8_t hash[RB_SSL_CERTFP_LEN]; const mbedtls_md_info_t *md_info; int ret; peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); if (peer_cert == NULL) return 0; md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); if (md_info == NULL) return 0; if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, hash)) != 0) { rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, %d", F, ret); return 0; } memcpy(certfp, hash, RB_SSL_CERTFP_LEN); return 1; }
static void rb_read_timerfd(rb_fde_t *F, void *data) { struct ev_entry *event = (struct ev_entry *)data; int retlen; uint64_t count; if(event == NULL) { rb_close(F); return; } retlen = rb_read(F, &count, sizeof(count)); if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) { rb_close(F); rb_lib_log("rb_read_timerfd: timerfd[%s] closed on error: %s", event->name, strerror(errno)); return; } rb_setselect(F, RB_SELECT_READ, rb_read_timerfd, event); rb_run_event(event); }
int rb_init_ssl(void) { int ret; mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { rb_lib_log("rb_init_prng: unable to initialize PRNG, mbedtls_ctr_drbg_seed() returned -0x%x", -ret); return 0; } #if 0 mbedtls_ssl_config_init(&serv_config); if ((ret = mbedtls_ssl_config_defaults(&serv_config, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for server context: -0x%x", -ret); return 0; } #endif // mbedtls_ssl_conf_rng(&serv_config, mbedtls_ctr_drbg_random, &ctr_drbg); /***************************************************************************************************************/ #if 0 mbedtls_ssl_config_init(&client_config); if ((ret = mbedtls_ssl_config_defaults(&client_config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for client context: -0x%x", -ret); return 0; } mbedtls_ssl_conf_rng(&client_config, mbedtls_ctr_drbg_random, &ctr_drbg); #endif return 1; }
/* * rb_setselect * * This is a needed exported function which will be called to register * and deregister interest in a pending IO state for a given FD. */ void rb_setselect_epoll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data) { struct epoll_event ep_event; int old_flags = F->pflags; int op = -1; lrb_assert(IsFDOpen(F)); /* Update the list, even though we're not using it .. */ if(type & RB_SELECT_READ) { if(handler != NULL) F->pflags |= EPOLLIN; else F->pflags &= ~EPOLLIN; F->read_handler = handler; F->read_data = client_data; } if(type & RB_SELECT_WRITE) { if(handler != NULL) F->pflags |= EPOLLOUT; else F->pflags &= ~EPOLLOUT; F->write_handler = handler; F->write_data = client_data; } if(old_flags == 0 && F->pflags == 0) return; else if(F->pflags <= 0) op = EPOLL_CTL_DEL; else if(old_flags == 0 && F->pflags > 0) op = EPOLL_CTL_ADD; else if(F->pflags != old_flags) op = EPOLL_CTL_MOD; if(op == -1) return; ep_event.events = F->pflags; ep_event.data.ptr = F; if(op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD) ep_event.events |= EPOLLET; if(epoll_ctl(ep_info->ep, op, F->fd, &ep_event) != 0) { rb_lib_log("rb_setselect_epoll(): epoll_ctl failed: %s", strerror(errno)); abort(); } }
void rb_outofmemory(void) { static int was_here = 0; if (was_here) abort(); was_here = 1; rb_lib_log("Out of memory: restarting server..."); rb_lib_restart("Out of Memory"); }
void rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) { ssl_connect_t *sconn; int ssl_err; if(F == NULL) return; sconn = rb_malloc(sizeof(ssl_connect_t)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; F->connect = rb_malloc(sizeof(struct conndata)); F->connect->callback = callback; F->connect->data = data; F->type |= RB_FD_SSL; F->ssl = SSL_new(F->sctx->ssl_ctx); if(F->ssl == NULL) { F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_start_Connected: SSL_new() fails: %s", ERR_error_string(F->sslerr.ssl_errno, NULL)); rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); return; } 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) { switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err)) { case SSL_ERROR_SYSCALL: if(rb_ignore_errno(errno)) case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: { F->sslerr.ssl_errno = get_last_err(); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, rb_ssl_tryconn_cb, sconn); return; } default: F->sslerr.ssl_errno = get_last_err(); rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); return; } } else { rb_ssl_connect_realcb(F, RB_OK, sconn); } }
int rb_init_ssl(void) { gnutls_global_init(); if (gnutls_certificate_allocate_credentials(&x509) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials"); return 0; } rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); return 1; }
int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) { int ret; gnutls_datum_t *d_cert, *d_key; if(cert == NULL) { rb_lib_log("rb_setup_ssl_server: No certificate file"); return 0; } if((d_cert = rb_load_file_into_datum_t(cert)) == NULL) { rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", strerror(errno)); return 0; } if((d_key = rb_load_file_into_datum_t(keyfile)) == NULL) { rb_lib_log("rb_setup_ssl_server: Error loading key: %s", strerror(errno)); return 0; } if((ret = gnutls_certificate_set_x509_key_mem(x509, d_cert, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_setup_ssl_server: Error loading certificate or key file: %s", gnutls_strerror(ret)); return 0; } rb_free_datum_t(d_cert); rb_free_datum_t(d_key); if(dhfile != NULL) { if(gnutls_dh_params_init(&dh_params) == GNUTLS_E_SUCCESS) { gnutls_datum_t *data; int xret; data = rb_load_file_into_datum_t(dhfile); if(data != NULL) { xret = gnutls_dh_params_import_pkcs3(dh_params, data, GNUTLS_X509_FMT_PEM); if(xret < 0) rb_lib_log ("rb_setup_ssl_server: Error parsing DH file: %s\n", gnutls_strerror(xret)); rb_free_datum_t(data); } gnutls_certificate_set_dh_params(x509, dh_params); } else rb_lib_log("rb_setup_ssl_server: Unable to setup DH parameters"); } return 1; }
int rb_ports_sched_event(struct ev_entry *event, int when) { timer_t *id; struct sigevent ev; port_notify_t not; struct itimerspec ts; event->comm_ptr = rb_malloc(sizeof(timer_t)); id = event->comm_ptr; memset(&ev, 0, sizeof(ev)); ev.sigev_notify = SIGEV_PORT; ev.sigev_value.sival_ptr = ¬ memset(¬, 0, sizeof(not)); not.portnfy_port = pe; not.portnfy_user = event; if(timer_create(CLOCK_REALTIME, &ev, id) < 0) { rb_lib_log("timer_create: %s\n", strerror(errno)); return 0; } memset(&ts, 0, sizeof(ts)); ts.it_value.tv_sec = when; ts.it_value.tv_nsec = 0; if(event->frequency != 0) ts.it_interval = ts.it_value; if(timer_settime(*id, 0, &ts, NULL) < 0) { rb_lib_log("timer_settime: %s\n", strerror(errno)); return 0; } return 1; }
static void rb_ssl_tryconn(rb_fde_t *F, int status, void *data) { ssl_connect_t *sconn = data; int ssl_err; if(status != RB_OK) { rb_ssl_connect_realcb(F, status, sconn); return; } F->type |= RB_FD_SSL; F->ssl = SSL_new(F->sctx->ssl_ctx); if(F->ssl == NULL) { F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_tryconn: SSL_new() fails: %s", ERR_error_string(F->sslerr.ssl_errno, NULL)); rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); return; } 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) { switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err)) { case SSL_ERROR_SYSCALL: if(rb_ignore_errno(errno)) case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: { F->sslerr.ssl_errno = get_last_err(); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, rb_ssl_tryconn_cb, sconn); return; } default: F->sslerr.ssl_errno = get_last_err(); rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); return; } } else { rb_ssl_connect_realcb(F, RB_OK, sconn); } }
static void rb_ssl_setup_client_context(rb_fde_t *F) { int ret; mbedtls_ssl_init(SSL_P(ssl)); if ((ret = mbedtls_ssl_setup(SSL_P(F), &F->sctx->config)) != 0) { rb_lib_log("rb_ssl_setup_client_context: failed to set up ssl context: -0x%x", -ret); rb_close(F); return; } mbedtls_ssl_set_bio(SSL_P(ssl), F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); }
/* * rb_init_netio * * This is a needed exported function which will be called to initialise * the network loop code. */ int rb_init_netio_devpoll(void) { dpfd = open("/dev/poll", O_RDWR); if(dpfd < 0) { return errno; } maxfd = getdtablesize() - 2; /* This makes more sense than HARD_FDLIMIT */ fdmask = rb_malloc(sizeof(fdmask) * maxfd + 1); if(rb_open(dpfd, RB_FD_UNKNOWN, "/dev/poll file descriptor") == NULL) { rb_lib_log("rb_init_netio_devpoll: Unable to rb_open /dev/poll fd"); return -1; } return 0; }
/* * Write an update to the devpoll filter. * See, we end up having to do a seperate (?) remove before we do an * add of a new polltype, so we have to have this function seperate from * the others. */ static void devpoll_write_update(int fd, int events) { struct pollfd pollfds[1]; /* Just to be careful */ int retval; /* Build the pollfd entry */ pollfds[0].revents = 0; pollfds[0].fd = fd; pollfds[0].events = events; /* Write the thing to our poll fd */ retval = write(dpfd, &pollfds[0], sizeof(struct pollfd)); if(retval != sizeof(struct pollfd)) rb_lib_log("devpoll_write_update: dpfd write failed %d: %s", errno, strerror(errno)); /* Done! */ }
int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile) { DH *dh; unsigned long err; if(cert == NULL) { rb_lib_log("rb_setup_ssl_server: No certificate file"); return 0; } if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert, get_ssl_error(err)); return 0; } if(keyfile == NULL) { rb_lib_log("rb_setup_ssl_server: No key file"); return 0; } 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)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile, get_ssl_error(err)); return 0; } if(dhfile != NULL) { /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */ BIO *bio = BIO_new_file(dhfile, "r"); if(bio != 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", dhfile, get_ssl_error(err)); BIO_free(bio); return 0; } BIO_free(bio); SSL_CTX_set_tmp_dh(ssl_server_ctx, dh); } else { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s", dhfile, get_ssl_error(err)); } } return 1; }
/* * rb_init_netio * * This is a needed exported function which will be called to initialise * the network loop code. */ int rb_init_netio_epoll(void) { can_do_event = 0; /* shut up gcc */ can_do_timerfd = 0; ep_info = rb_malloc(sizeof(struct epoll_info)); ep_info->pfd_size = getdtablesize(); ep_info->ep = epoll_create(ep_info->pfd_size); if(ep_info->ep < 0) { return -1; } if(rb_open(ep_info->ep, RB_FD_UNKNOWN, "epoll file descriptor") == NULL) { rb_lib_log("Unable to rb_open epoll fd"); return -1; } ep_info->pfd = rb_malloc(sizeof(struct epoll_event) * ep_info->pfd_size); return 0; }
/* * rb_init_netio * * This is a needed exported function which will be called to initialise * the network loop code. */ int rb_init_netio_kqueue(void) { kq = kqueue(); if(kq < 0) { return errno; } kqmax = getdtablesize(); kqlst = rb_malloc(sizeof(struct kevent) * kqmax); kqout = rb_malloc(sizeof(struct kevent) * kqmax); if(rb_open(kq, RB_FD_UNKNOWN, "kqueue fd") == NULL) { rb_lib_log("rb_init_netio_kqueue: unable to rb_open kqueue fd"); return -1; } zero_timespec.tv_sec = 0; zero_timespec.tv_nsec = 0; return 0; }
int rb_init_ssl(void) { gnutls_global_init(); if(gnutls_certificate_allocate_credentials(&x509) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials"); return 0; } #if GNUTLS_VERSION_MAJOR < 3 gnutls_certificate_client_set_retrieve_function(x509, cert_callback); #else gnutls_certificate_set_retrieve_function(x509, cert_callback); #endif #if (GNUTLS_VERSION_MAJOR < 3) rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); #endif return 1; }
static void kq_update_events(rb_fde_t *F, short filter, PF * handler) { PF *cur_handler; int kep_flags; switch (filter) { case EVFILT_READ: cur_handler = F->read_handler; break; case EVFILT_WRITE: cur_handler = F->write_handler; break; default: /* XXX bad! -- adrian */ return; break; } if((cur_handler == NULL && handler != NULL) || (cur_handler != NULL && handler == NULL)) { struct kevent *kep; kep = kqlst + kqoff; if(handler != NULL) { kep_flags = EV_ADD | EV_ONESHOT; } else { kep_flags = EV_DELETE; } EV_SET(kep, (uintptr_t)F->fd, filter, kep_flags, 0, 0, (void *)F); if(++kqoff == kqmax) { int ret, i; /* Add them one at a time, because there may be * already closed fds in it. The kernel will try * to report invalid fds in the output; if there * is no space, it silently stops processing the * array at that point. We cannot give output space * because that would also return events we cannot * process at this point. */ for(i = 0; i < kqoff; i++) { ret = kevent(kq, kqlst + i, 1, NULL, 0, &zero_timespec); /* jdc -- someone needs to do error checking... */ /* EBADF is normal here -- jilles */ if(ret == -1 && errno != EBADF) rb_lib_log("kq_update_events(): kevent(): %s", strerror(errno)); } kqoff = 0; } } }
int rb_init_ssl(void) { int ret = 1; char libratbox_data[] = "libratbox data"; const char libratbox_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; SSL_load_error_strings(); SSL_library_init(); libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL); #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) ssl_server_ctx = SSL_CTX_new(SSLv23_server_method()); #else ssl_server_ctx = SSL_CTX_new(TLS_server_method()); #endif if(ssl_server_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", get_ssl_error(ERR_get_error())); ret = 0; } long server_options = SSL_CTX_get_options(ssl_server_ctx); #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) server_options |= SSL_OP_NO_SSLv2; server_options |= SSL_OP_NO_SSLv3; #endif #ifdef SSL_OP_SINGLE_DH_USE server_options |= SSL_OP_SINGLE_DH_USE; #endif #ifdef SSL_OP_SINGLE_ECDH_USE server_options |= SSL_OP_SINGLE_ECDH_USE; #endif #ifdef SSL_OP_NO_TICKET server_options |= SSL_OP_NO_TICKET; #endif server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; SSL_CTX_set_options(ssl_server_ctx, server_options); SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_cipher_list(ssl_server_ctx, libratbox_ciphers); /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks and bastardise their OpenSSL for stupid reasons... */ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && defined(NID_secp384r1) EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1); if (key) { SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key); EC_KEY_free(key); } #endif #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) ssl_client_ctx = SSL_CTX_new(TLSv1_client_method()); #else ssl_client_ctx = SSL_CTX_new(TLS_client_method()); #endif if(ssl_client_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s", get_ssl_error(ERR_get_error())); ret = 0; } #ifdef SSL_OP_NO_TICKET SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET); #endif SSL_CTX_set_cipher_list(ssl_client_ctx, libratbox_ciphers); return ret; }
rb_ssl_ctx * rb_setup_ssl_server(const char *cacert, const char *cert, const char *keyfile, const char *dhfile, const char *ssl_cipher_list, const char *named_curve, rb_tls_ver_t tls_min_ver) { int ret; rb_ssl_ctx *sctx; sctx = rb_malloc(sizeof(rb_ssl_ctx)); mbedtls_ssl_config_init(&sctx->config); // mbedtls_entropy_init(&sctx->entropy); // mbedtls_ctr_drbg_init(&sctx->ctr_drbg); mbedtls_ssl_conf_rng(&sctx->config, mbedtls_ctr_drbg_random, &ctr_drbg); if ((ret = mbedtls_ssl_config_defaults(&sctx->config, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { rb_lib_log("rb_init_ssl: unable to initialize default SSL parameters for server context: -0x%x", -ret); return 0; } mbedtls_ssl_conf_rng(&sctx->config, mbedtls_ctr_drbg_random, &ctr_drbg); if(cacert != NULL) { mbedtls_x509_crt_init(&sctx->cacert); ret = mbedtls_x509_crt_parse_file(&sctx->cacert, cacert); if(ret != 0) { rb_lib_log("rb_setup_ssl_server: failed to parse CA certificate '%s': -0x%x", cert, -ret); return 0; } } mbedtls_x509_crt_init(&sctx->x509); ret = mbedtls_x509_crt_parse_file(&sctx->x509, cert); if (ret != 0) { rb_lib_log("rb_setup_ssl_server: failed to parse certificate '%s': -0x%x", cert, -ret); return 0; } mbedtls_pk_init(&sctx->serv_pk); ret = mbedtls_pk_parse_keyfile(&sctx->serv_pk, keyfile, NULL); if (ret != 0) { rb_lib_log("rb_setup_ssl_server: failed to parse private key '%s': -0x%x", keyfile, -ret); return 0; } mbedtls_dhm_init(&sctx->dh_params); ret = mbedtls_dhm_parse_dhmfile(&sctx->dh_params, dhfile); if (ret != 0) { rb_lib_log("rb_setup_ssl_server: failed to parse DH parameters '%s': -0x%x", dhfile, -ret); return 0; } ret = mbedtls_ssl_conf_dh_param_ctx(&sctx->config, &sctx->dh_params); if (ret != 0) { rb_lib_log("rb_setup_ssl_server: failed to set DH parameters on SSL config context: -0x%x", -ret); return 0; } if (&sctx->x509.next) mbedtls_ssl_conf_ca_chain(&sctx->config, sctx->x509.next, NULL); mbedtls_ssl_conf_ca_chain(&sctx->config, &sctx->cacert, NULL); if ((ret = mbedtls_ssl_conf_own_cert(&sctx->config, &sctx->x509, &sctx->serv_pk)) != 0) { rb_lib_log("rb_setup_ssl_server: failed to set up own certificate: -0x%x", -ret); return 0; } return sctx; }
rb_ssl_ctx * rb_setup_ssl_server(const char *cacert, const char *cert, const char *keyfile, const char *dhfile, const char *ssl_cipher_list, const char *named_curve, rb_tls_ver_t tls_min_ver) { const char *libratbox_data = "libratbox tls session"; const char *ciphers = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; unsigned long err; rb_ssl_ctx *sctx; long tls_opts; sctx = rb_malloc(sizeof(rb_ssl_ctx)); sctx->refcount = 1; sctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if(sctx->ssl_ctx == NULL) { rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s", ERR_error_string(ERR_get_error(), NULL)); rb_free(sctx); return NULL; } tls_opts = SSL_CTX_get_options(sctx->ssl_ctx); /* Disable SSLv2, make the client use our settings */ tls_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE; switch(tls_min_ver) { case RB_TLS_VER_SSL3: /* we default to SSLv3..sadly */ break; case RB_TLS_VER_TLS1: #ifdef SSL_OP_NO_SSLv3 tls_opts |= SSL_OP_NO_SSLv3; #endif break; case RB_TLS_VER_TLS1_1: #ifdef SSL_OP_NO_TLSv1 tls_opts |= SSL_OP_NO_TLSv1; #endif break; case RB_TLS_VER_TLS1_2: #ifdef SSL_OP_NO_TLSv1 tls_opts |= SSL_OP_NO_TLSv1; #endif #ifdef SSL_OP_NO_TLSv1_1 tls_opts |= SSL_OP_NO_TLSv1_1; #endif break; case RB_TLS_VER_LAST: break; } #ifdef SSL_OP_SINGLE_DH_USE tls_opts |= SSL_OP_SINGLE_DH_USE; #endif #ifdef SSL_OP_SINGLE_ECDH_USE tls_opts |= SSL_OP_SINGLE_ECDH_USE; #endif #ifdef SSL_OP_NO_TICKET tls_opts |= SSL_OP_NO_TICKET; #endif SSL_CTX_set_options(sctx->ssl_ctx, tls_opts); if(ssl_cipher_list != NULL) ciphers = ssl_cipher_list; if(!SSL_CTX_set_cipher_list(sctx->ssl_ctx, ciphers)) { rb_lib_log("rb_setup_ssl_server: Error setting ssl_cipher_list=\"%s\": %s", ciphers, ERR_error_string(ERR_get_error(), NULL)); goto cleanup;; } if(cert == NULL) { rb_lib_log("rb_setup_ssl_server: No certificate file"); goto cleanup; } if(!SSL_CTX_use_certificate_chain_file(sctx->ssl_ctx, cert)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert, ERR_error_string(err, NULL)); goto cleanup; } if(cacert != NULL) { if (!SSL_CTX_load_verify_locations(sctx->ssl_ctx, cacert, NULL)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading CA file [%s]: %s", cacert, ERR_error_string(err, NULL)); goto cleanup; } } if(keyfile == NULL) { rb_lib_log("rb_setup_ssl_server: No key file"); goto cleanup; } if(!SSL_CTX_use_PrivateKey_file(sctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM)) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile, ERR_error_string(err, NULL)); goto cleanup;; } if(dhfile != NULL) { /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */ BIO *bio = BIO_new_file(dhfile, "r"); if(bio != NULL) { DH *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", dhfile, ERR_error_string(err, NULL)); BIO_free(bio); goto cleanup; } BIO_free(bio); SSL_CTX_set_tmp_dh(sctx->ssl_ctx, dh); DH_free(dh); } 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)); goto cleanup; } } #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH if(named_curve != NULL) { int nid; EC_KEY *ecdh; nid = OBJ_sn2nid(named_curve); if(nid == 0) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Unknown curve named [%s]: %s", named_curve, ERR_error_string(err, NULL)); goto cleanup; } ecdh = EC_KEY_new_by_curve_name(nid); if(ecdh == NULL) { err = ERR_get_error(); rb_lib_log("rb_setup_ssl_server: Curve creation failed for [%s]: %s", named_curve, ERR_error_string(err, NULL)); goto cleanup; } SSL_CTX_set_options(sctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(sctx->ssl_ctx, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_verify(sctx->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); SSL_CTX_set_session_id_context(sctx->ssl_ctx, (const unsigned char *)libratbox_data, strlen(libratbox_data)); return sctx; cleanup: SSL_CTX_free(sctx->ssl_ctx); rb_free(sctx); return NULL; }
int rb_select_epoll(long delay) { int num, i, flags, old_flags, op; struct epoll_event ep_event; int o_errno; void *data; num = epoll_wait(ep_info->ep, ep_info->pfd, ep_info->pfd_size, delay); /* save errno as rb_set_time() will likely clobber it */ o_errno = errno; rb_set_time(); errno = o_errno; if(num < 0 && !rb_ignore_errno(o_errno)) return RB_ERROR; if(num <= 0) return RB_OK; for(i = 0; i < num; i++) { PF *hdl; rb_fde_t *F = ep_info->pfd[i].data.ptr; old_flags = F->pflags; if(ep_info->pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) { hdl = F->read_handler; data = F->read_data; F->read_handler = NULL; F->read_data = NULL; if(hdl) { hdl(F, data); } } if(!IsFDOpen(F)) continue; if(ep_info->pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) { hdl = F->write_handler; data = F->write_data; F->write_handler = NULL; F->write_data = NULL; if(hdl) { hdl(F, data); } } if(!IsFDOpen(F)) continue; flags = 0; if(F->read_handler != NULL) flags |= EPOLLIN; if(F->write_handler != NULL) flags |= EPOLLOUT; if(old_flags != flags) { if(flags == 0) op = EPOLL_CTL_DEL; else op = EPOLL_CTL_MOD; F->pflags = ep_event.events = flags; ep_event.data.ptr = F; if(op == EPOLL_CTL_MOD || op == EPOLL_CTL_ADD) ep_event.events |= EPOLLET; if(epoll_ctl(ep_info->ep, op, F->fd, &ep_event) != 0) { rb_lib_log("rb_select_epoll(): epoll_ctl failed: %s", strerror(errno)); } } } return RB_OK; }