//#ifdef USE_SSL //#include "netinc.h" //#include "util.h" //#include "connection.h" #include "wac_network_ssl_connection.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, api_dns *dns, size_t sendbufsize, size_t recvbufsize ) : WAC_Network_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 = WAC_Network_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 */ } } // 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 ); WAC_Network_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; } } WAC_Network_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 = _strdup( "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