#include "netinc.h" #include "util.h" #include "connection.h" #include "sslconnection.h" #ifdef _JNETLIB_SSL_ SSL_CTX *sslContext = 0; #ifdef _DEBUG extern "C" void apps_ssl_info_callback (const SSL * s, int where, int ret) { /* ** DEBUG INFO HERE */ } #endif /* ** Well, you should probably change this based on like... ** well, you're level of trust heh ** For now, this basically trusts all certs :) ** */ extern "C" int verify_callback(int ok, X509_STORE_CTX * ctx) { /* For certificate verification */ int verify_depth = 0; int verify_error = X509_V_OK; char buf[1024]; X509 * err_cert = X509_STORE_CTX_get_current_cert(ctx); int err = X509_STORE_CTX_get_error(ctx); int depth = X509_STORE_CTX_get_error_depth(ctx); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); if (!ok) { if (verify_depth >= depth) { ok = 1; verify_error = X509_V_OK; } else { ok = 0; verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; } } switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, sizeof(buf)); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: break; } return ok; } JNL_SSL_Connection::JNL_SSL_Connection(SSL* pssl, JNL_AsyncDNS *dns, int sendbufsize, int recvbufsize) : JNL_Connection(dns, sendbufsize, recvbufsize), forceConnect(false) { m_ssl = pssl; m_bsslinit = false; if (m_ssl) { m_bcontextowned = false; } else { m_bcontextowned = true; } if (m_bcontextowned == false) { return ; } m_bsslinit = true; /* See the SSL states in our own callback */ #ifdef _DEBUG // SSL_CTX_set_info_callback(m_app_ctx, apps_ssl_info_callback); #endif /* Set the certificate verification callback */ //SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER, verify_callback); /* Not sure what this does */ //SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_CLIENT); if(sslContext == NULL) { SSL_METHOD * meth = NULL; SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); meth = SSLv23_client_method(); if ((sslContext = SSL_CTX_new(meth)) == NULL) { return; } } return ; } int JNL_SSL_Connection::socket_connect() { int retval; if (m_bcontextowned == false) { /* ** WTF? */ return -1; } if (m_ssl != NULL) { return -1; } retval = JNL_Connection::socket_connect(); if (retval != 0) { if (ERRNO != EINPROGRESS) { return retval; // benski> if the underlying socket hasn't connected yet, then we can't start the SSL connection /* ** Joshua Teitelbaum 3/2/2006 ** Fatal error here */ } } m_ssl = SSL_new(sslContext); if (m_ssl == NULL) { return -1; } /* Tell that we are in connect mode */ SSL_set_connect_state(m_ssl); /* Set socket descriptor with the socket we already have open */ if(SSL_set_fd(m_ssl, m_socket) != 0) { return -1; } return retval; } void JNL_SSL_Connection::socket_shutdown() { if (m_ssl) SSL_shutdown(m_ssl); JNL_Connection::socket_shutdown(); if (m_ssl) { SSL_free(m_ssl); m_ssl = NULL; } return ; } void JNL_SSL_Connection::run(int max_send_bytes, int max_recv_bytes, int *bytes_sent, int *bytes_rcvd) { if (!m_bsslinit) { int rval = 0; int e = 0; rval = SSL_accept(m_ssl); if (rval == -1) { e = SSL_get_error(m_ssl, rval); if (!((e == SSL_ERROR_WANT_READ) || (e == SSL_ERROR_WANT_WRITE))) { m_state = STATE_ERROR; } return ; } else { m_bsslinit = true; } } /** ** benski - march 2, 2006 **if the underlying socket didn't connected yet, we need to try the SSL connection again */ if (forceConnect) { if(init_ssl_connection() == false) { return; } } JNL_Connection::run(max_send_bytes, max_recv_bytes, bytes_sent, bytes_rcvd); } /* ** init_ssl_connection: ** Returns true, meaning can continue ** Else, cannot continue with underlying run ** side effects: ** sets forceConnect */ bool JNL_SSL_Connection::init_ssl_connection() { if(m_ssl == NULL) { /* ** WTF? ** cascade up. */ return true; } int retval = SSL_connect(m_ssl); if (retval < 0) { int err = SSL_get_error(m_ssl, retval); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CONNECT: forceConnect = true; break; // fall through default: // TODO: benski> MOST other errors are OK, (especially "want read" and "want write", but we need to think through all the scenarios here forceConnect=false; } } else if(retval) { /* ** success */ forceConnect = false; } /* ** If retval == 0 ** socket is closed, or serious error occurred. ** cascade up. */ return forceConnect==false; } void JNL_SSL_Connection::on_socket_connected(void) { init_ssl_connection(); } void JNL_SSL_Connection::connect(int s, struct sockaddr_in *loc) { /* ** Joshua Teitelbaum 2/01/2006 ** No need to close ** This is the reason for divergence as well as setting ** the connect state */ m_socket = s; m_remote_port = 0; m_dns = NULL; if (loc) *m_saddr = *loc; else memset(m_saddr, 0, sizeof(m_saddr)); if (m_socket != -1) { SET_SOCK_BLOCK(m_socket, 0); m_state = STATE_CONNECTED; SSL_set_fd(m_ssl, m_socket); } else { m_errorstr = "invalid socket passed to connect"; m_state = STATE_ERROR; } } int JNL_SSL_Connection::socket_recv(char *buf, int len, int options) { return SSL_read(m_ssl, buf, len); } int JNL_SSL_Connection::socket_send(char *buf, int len, int options) { return SSL_write(m_ssl, buf, len); } JNL_SSL_Connection::~JNL_SSL_Connection() { if (m_ssl) { SSL_free(m_ssl); m_ssl = NULL; } } #endif