//#ifdef USE_SSL //#include "netinc.h" //#include "util.h" //#include "connection.h" #include "sslconnection.h" 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 :) ** */ #if 0 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] = {0}; 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; } #endif JNL_SSL_Connection::JNL_SSL_Connection() : forceConnect(false), m_ssl(0), m_bsslinit(false), m_bcontextowned(true) { m_bsslinit = true; } JNL_SSL_Connection::JNL_SSL_Connection(SSL* pssl, JNL_AsyncDNS *dns, size_t sendbufsize, size_t 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); 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 != JNL_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 */ } } // moved from InitSSL() as no need to create this unless // we're actually going to use it which helps slow loads if (!sslContext) { sslContext = SSL_CTX_new(SSLv23_client_method()); if (sslContext) { SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } else { return -1; } } 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(size_t max_send_bytes, size_t max_recv_bytes, size_t *bytes_sent, size_t *bytes_rcvd) { if (!m_bsslinit) { int rval = SSL_accept(m_ssl); if (rval == -1) { int 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(SOCKET s, sockaddr *addr, socklen_t length) { /* ** 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; address=(sockaddr *)malloc(length); memcpy(address, addr, length); m_remote_port = 0; 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; } } ssize_t JNL_SSL_Connection::socket_recv(char *buf, size_t len, int options) { return SSL_read(m_ssl, buf, (int)len); } ssize_t JNL_SSL_Connection::socket_send(const char *buf, size_t len, int options) { return SSL_write(m_ssl, buf, (int)len); } JNL_SSL_Connection::~JNL_SSL_Connection() { if (m_ssl) { SSL_free(m_ssl); m_ssl = NULL; } } //#endif