mirror of
https://github.com/irssi/irssi.git
synced 2024-12-04 14:46:39 -05:00
Rewrite SSL connection/handshake code.
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@4536 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
parent
5bcafebbd4
commit
273152762f
@ -38,7 +38,6 @@ typedef struct
|
|||||||
GIOChannel *giochan;
|
GIOChannel *giochan;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
SSL_CTX *ctx;
|
SSL_CTX *ctx;
|
||||||
unsigned int got_cert:1;
|
|
||||||
unsigned int verify:1;
|
unsigned int verify:1;
|
||||||
} GIOSSLChannel;
|
} GIOSSLChannel;
|
||||||
|
|
||||||
@ -110,45 +109,11 @@ static GIOStatus ssl_errno(gint e)
|
|||||||
return G_IO_STATUS_ERROR;
|
return G_IO_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GIOStatus irssi_ssl_cert_step(GIOSSLChannel *chan)
|
|
||||||
{
|
|
||||||
X509 *cert;
|
|
||||||
gint err;
|
|
||||||
switch(err = SSL_do_handshake(chan->ssl))
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if(!(cert = SSL_get_peer_certificate(chan->ssl)))
|
|
||||||
{
|
|
||||||
g_warning("SSL server supplied no certificate");
|
|
||||||
return G_IO_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
if (chan->verify && ! irssi_ssl_verify(chan->ssl, chan->ctx, cert)) {
|
|
||||||
X509_free(cert);
|
|
||||||
return G_IO_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
X509_free(cert);
|
|
||||||
return G_IO_STATUS_NORMAL;
|
|
||||||
default:
|
|
||||||
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
|
|
||||||
return G_IO_STATUS_AGAIN;
|
|
||||||
return ssl_errno(errno);
|
|
||||||
}
|
|
||||||
/*UNREACH*/
|
|
||||||
return G_IO_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
|
static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
|
||||||
{
|
{
|
||||||
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
|
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
|
||||||
gint err;
|
gint err;
|
||||||
|
|
||||||
if(! chan->got_cert)
|
|
||||||
{
|
|
||||||
gint cert_err = irssi_ssl_cert_step(chan);
|
|
||||||
if(cert_err != G_IO_STATUS_NORMAL)
|
|
||||||
return cert_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = SSL_read(chan->ssl, buf, len);
|
err = SSL_read(chan->ssl, buf, len);
|
||||||
if(err < 0)
|
if(err < 0)
|
||||||
{
|
{
|
||||||
@ -171,13 +136,6 @@ static GIOStatus irssi_ssl_write(GIOChannel *handle, const gchar *buf, gsize len
|
|||||||
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
|
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
|
||||||
gint err;
|
gint err;
|
||||||
|
|
||||||
if(! chan->got_cert)
|
|
||||||
{
|
|
||||||
gint cert_err = irssi_ssl_cert_step(chan);
|
|
||||||
if(cert_err != G_IO_STATUS_NORMAL)
|
|
||||||
return cert_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = SSL_write(chan->ssl, (const char *)buf, len);
|
err = SSL_write(chan->ssl, (const char *)buf, len);
|
||||||
if(err < 0)
|
if(err < 0)
|
||||||
{
|
{
|
||||||
@ -265,7 +223,6 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycer
|
|||||||
GIOChannel *gchan;
|
GIOChannel *gchan;
|
||||||
int err, fd;
|
int err, fd;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
X509 *cert = NULL;
|
|
||||||
SSL_CTX *ctx = NULL;
|
SSL_CTX *ctx = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail(handle != NULL, NULL);
|
g_return_val_if_fail(handle != NULL, NULL);
|
||||||
@ -336,47 +293,11 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycer
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((err = SSL_connect(ssl)) <= 0)
|
|
||||||
{
|
|
||||||
switch(err = SSL_get_error(ssl, err))
|
|
||||||
{
|
|
||||||
case SSL_ERROR_SYSCALL:
|
|
||||||
if(errno == EINTR || errno == EAGAIN)
|
|
||||||
case SSL_ERROR_WANT_READ:
|
|
||||||
case SSL_ERROR_WANT_WRITE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SSL_free(ssl);
|
|
||||||
if (ctx != ssl_ctx)
|
|
||||||
SSL_CTX_free(ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(!(cert = SSL_get_peer_certificate(ssl)))
|
|
||||||
{
|
|
||||||
g_warning("SSL server supplied no certificate");
|
|
||||||
if (ctx != ssl_ctx)
|
|
||||||
SSL_CTX_free(ctx);
|
|
||||||
SSL_free(ssl);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (verify && ! irssi_ssl_verify(ssl, ctx, cert)) {
|
|
||||||
SSL_free(ssl);
|
|
||||||
if (ctx != ssl_ctx)
|
|
||||||
SSL_CTX_free(ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
X509_free(cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
chan = g_new0(GIOSSLChannel, 1);
|
chan = g_new0(GIOSSLChannel, 1);
|
||||||
chan->fd = fd;
|
chan->fd = fd;
|
||||||
chan->giochan = handle;
|
chan->giochan = handle;
|
||||||
chan->ssl = ssl;
|
chan->ssl = ssl;
|
||||||
chan->ctx = ctx;
|
chan->ctx = ctx;
|
||||||
chan->got_cert = cert != NULL;
|
|
||||||
chan->verify = verify;
|
chan->verify = verify;
|
||||||
|
|
||||||
gchan = (GIOChannel *)chan;
|
gchan = (GIOChannel *)chan;
|
||||||
@ -397,6 +318,32 @@ GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *
|
|||||||
return ssl_handle;
|
return ssl_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int irssi_ssl_handshake(GIOChannel *handle)
|
||||||
|
{
|
||||||
|
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
|
||||||
|
int ret, err;
|
||||||
|
X509 *cert;
|
||||||
|
|
||||||
|
ret = SSL_connect(chan->ssl);
|
||||||
|
if (ret <= 0) {
|
||||||
|
err = SSL_get_error(chan->ssl, ret);
|
||||||
|
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
||||||
|
g_warning(ERR_reason_error_string(ERR_get_error()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return err == SSL_ERROR_WANT_READ ? 1 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(chan->ssl);
|
||||||
|
if (cert == NULL) {
|
||||||
|
g_warning("SSL server supplied no certificate");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, cert);
|
||||||
|
X509_free(cert);
|
||||||
|
return ret ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* HAVE_OPENSSL */
|
#else /* HAVE_OPENSSL */
|
||||||
|
|
||||||
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
|
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
|
||||||
|
@ -48,6 +48,7 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
|
|||||||
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
|
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
|
||||||
/* Connect to socket with ip address and SSL*/
|
/* Connect to socket with ip address and SSL*/
|
||||||
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
|
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
|
||||||
|
int irssi_ssl_handshake(GIOChannel *handle);
|
||||||
/* Connect to socket with ip address */
|
/* Connect to socket with ip address */
|
||||||
GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
|
GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
|
||||||
/* Connect to named UNIX socket */
|
/* Connect to named UNIX socket */
|
||||||
|
@ -167,6 +167,39 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle)
|
|||||||
server_connect_finished(server);
|
server_connect_finished(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *handle)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
g_return_if_fail(IS_SERVER(server));
|
||||||
|
|
||||||
|
error = irssi_ssl_handshake(handle);
|
||||||
|
if (error == -1) {
|
||||||
|
server->connection_lost = TRUE;
|
||||||
|
server_connect_failed(server, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (error & 1) {
|
||||||
|
if (server->connect_tag != -1)
|
||||||
|
g_source_remove(server->connect_tag);
|
||||||
|
server->connect_tag = g_input_add(handle, error == 1 ? G_INPUT_READ : G_INPUT_WRITE,
|
||||||
|
(GInputFunction)
|
||||||
|
server_connect_callback_init_ssl,
|
||||||
|
server);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup_servers = g_slist_remove(lookup_servers, server);
|
||||||
|
if (server->connect_tag != -1) {
|
||||||
|
g_source_remove(server->connect_tag);
|
||||||
|
server->connect_tag = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_connect_finished(server);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void server_real_connect(SERVER_REC *server, IPADDR *ip,
|
static void server_real_connect(SERVER_REC *server, IPADDR *ip,
|
||||||
const char *unix_socket)
|
const char *unix_socket)
|
||||||
{
|
{
|
||||||
@ -218,6 +251,11 @@ server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_v
|
|||||||
g_free(errmsg2);
|
g_free(errmsg2);
|
||||||
} else {
|
} else {
|
||||||
server->handle = net_sendbuffer_create(handle, 0);
|
server->handle = net_sendbuffer_create(handle, 0);
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
if (server->connrec->use_ssl)
|
||||||
|
server_connect_callback_init_ssl(server, handle);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
server->connect_tag =
|
server->connect_tag =
|
||||||
g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ,
|
g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ,
|
||||||
(GInputFunction)
|
(GInputFunction)
|
||||||
|
Loading…
Reference in New Issue
Block a user