static int ssl_check_error(SSL *ssl, int ret) { int error; error = SSL_get_error(ssl, ret); switch (error) { case SSL_ERROR_NONE: return (0); case SSL_ERROR_WANT_READ: pjdlog_debug(2, "SSL_ERROR_WANT_READ"); return (-1); case SSL_ERROR_WANT_WRITE: pjdlog_debug(2, "SSL_ERROR_WANT_WRITE"); return (-1); case SSL_ERROR_ZERO_RETURN: pjdlog_exitx(EX_OK, "Connection closed."); case SSL_ERROR_SYSCALL: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "SSL I/O error."); case SSL_ERROR_SSL: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "SSL protocol error."); default: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "Unknown SSL error (%d).", error); } }
static void tls_exec_server(const char *user, int startfd, const char *privkey, const char *cert, int debuglevel) { SSL_CTX *sslctx; SSL *ssl; int sockfd, tcpfd, ret; pjdlog_debug_set(debuglevel); pjdlog_prefix_set("[TLS sandbox] (server) "); #ifdef HAVE_SETPROCTITLE setproctitle("[TLS sandbox] (server) "); #endif sockfd = startfd; tcpfd = startfd + 1; SSL_load_error_strings(); SSL_library_init(); sslctx = SSL_CTX_new(TLSv1_server_method()); if (sslctx == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed."); SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); ssl = SSL_new(sslctx); if (ssl == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed."); if (SSL_use_RSAPrivateKey_file(ssl, privkey, SSL_FILETYPE_PEM) != 1) { ssl_log_errors(); pjdlog_exitx(EX_CONFIG, "SSL_use_RSAPrivateKey_file(%s) failed.", privkey); } if (SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM) != 1) { ssl_log_errors(); pjdlog_exitx(EX_CONFIG, "SSL_use_certificate_file(%s) failed.", cert); } if (sandbox(user, true, "proto_tls server") != 0) pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS server."); pjdlog_debug(1, "Privileges successfully dropped."); nonblock(sockfd); nonblock(tcpfd); if (SSL_set_fd(ssl, tcpfd) != 1) pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed."); ret = SSL_accept(ssl); ssl_check_error(ssl, ret); tls_loop(sockfd, ssl); }
static X509* load_cert(const char* cert, size_t cert_size) { BIO* bio = BIO_new_mem_buf(const_cast<char*>(cert), cert_size); if (bio == NULL) { return NULL; } X509* x509 = PEM_read_bio_X509(bio, NULL, pem_password_callback, NULL); if (x509 == NULL) { ssl_log_errors("Unable to load certificate"); } BIO_free_all(bio); return x509; }
static EVP_PKEY* load_key(const char* key, size_t key_size, const char* password) { BIO* bio = BIO_new_mem_buf(const_cast<char*>(key), key_size); if (bio == NULL) { return NULL; } EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, NULL, pem_password_callback, const_cast<char*>(password)); if (pkey == NULL) { ssl_log_errors("Unable to load private key"); } BIO_free_all(bio); return pkey; }
// This starts a new TCP/TLS connection to notblocked // It is called both when a new local proxy connection is accepted // and when we need to re-open an existing telex transport (state->local is reused) void make_new_telex_conn(struct telex_state *state) { struct telex_conf *conf = state->conf; HexDump(LOG_TRACE, state->name, "Opening telex id:", state->remote_conn_id, sizeof(state->remote_conn_id)); state->remotetcp = bufferevent_socket_new(state->base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!state->remotetcp) { LogError(state->name, "Could not create remote bufferevent socket"); StateCleanup(&state); return; } _inc(BEV); // TODO: make nonblocking lookup? bufferevent_socket_connect_hostname(state->remotetcp, NULL, AF_INET, conf->notblocked_host, conf->notblocked_port); // After resolution... /* struct sockaddr_in sin; if (getpeername(bufferevent_getfd(state->remotetcp), (struct sockaddr *)&sin, (socklen_t*)sizeof(sin)) < 0) { perror("getpeername"); LogError("proxy", "getpeername failed"); StateCleanup(&state); return; } char ip_p[INET_ADDRSTRLEN]; LogTrace(state->name, "Connecting to %s:%d", evutil_inet_ntop(AF_INET, server_ip, ip_p, sizeof(ip_p)), state->conf->notblocked_port); //bufferevent_socket_connect(state->remotetcp, ai->ai_addr, (int)ai->ai_addrlen); */ if (ssl_new_telex(state) < 0) { ssl_log_errors(LOG_ERROR, state->name); LogError(state->name, "Could not create new telex SSL connection object"); StateCleanup(&state); return; } _inc(SSL); state->remote = bufferevent_openssl_filter_new(state->base, state->remotetcp, state->ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); // Not BEV_OPT_CLOSE_ON_FREE! if (!state->remote) { LogError(state->name, "Could not create remote SSL bufferevent filter"); StateCleanup(&state); return; } _inc(BEV); // First, set our read_cb to something that receives the SPTelex init message bufferevent_setcb(state->remote, (bufferevent_data_cb)first_read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Disable until SPTelex init msg bufferevent_disable(state->local, EV_READ|EV_WRITE); bufferevent_setcb(state->local, (bufferevent_data_cb)read_cb, NULL, (bufferevent_event_cb)event_cb, state); // Hmm...we should make a second one of these state->in_local = 0; }