325 lines
6.0 KiB
C++
Executable File
325 lines
6.0 KiB
C++
Executable File
#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
|