2 network-ssl.c : SSL support
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <openssl/crypto.h>
27 #include <openssl/x509.h>
28 #include <openssl/pem.h>
29 #include <openssl/ssl.h>
30 #include <openssl/err.h>
33 GIOError irssi_ssl_read(GIOChannel *, gchar *, guint, guint *);
35 GIOError irssi_ssl_write(GIOChannel *, gchar *, guint, guint*);
37 GIOError irssi_ssl_seek(GIOChannel *, gint, GSeekType);
39 void irssi_ssl_close(GIOChannel *);
40 #if GLIB_MAJOR_VERSION < 2
41 /* ssl create watch */
42 guint irssi_ssl_create_watch(GIOChannel *, gint, GIOCondition, GIOFunc, gpointer, GDestroyNotify);
44 GSource *irssi_ssl_create_watch(GIOChannel *, GIOCondition);
47 void irssi_ssl_free(GIOChannel *);
49 /* ssl i/o channel object */
59 /* ssl function pointers */
60 GIOFuncs irssi_ssl_channel_funcs =
66 irssi_ssl_create_watch,
70 SSL_CTX *ssl_ctx = NULL;
75 gint ssl_errno(gint e)
80 return G_IO_ERROR_INVAL;
83 return G_IO_ERROR_AGAIN;
85 return G_IO_ERROR_INVAL;
91 gboolean irssi_ssl_cert_step(GIOSSLChannel *chan)
94 switch(err = SSL_do_handshake(chan->ssl))
97 if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
99 g_warning("SSL server supplied no certificate");
100 return G_IO_ERROR_INVAL;
102 return G_IO_ERROR_NONE;
104 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
105 return G_IO_ERROR_AGAIN;
106 return ssl_errno(errno);
112 GIOError irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret)
114 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
117 if(chan->cert == NULL)
119 gint cert_err = irssi_ssl_cert_step(chan);
120 if(cert_err != G_IO_ERROR_NONE)
124 err = SSL_read(chan->ssl, buf, len);
128 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
129 return G_IO_ERROR_AGAIN;
130 return ssl_errno(errno);
135 return G_IO_ERROR_NONE;
141 GIOError irssi_ssl_write(GIOChannel *handle, gchar *buf, guint len, guint *ret)
143 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
146 if(chan->cert == NULL)
148 gint cert_err = irssi_ssl_cert_step(chan);
149 if(cert_err != G_IO_ERROR_NONE)
154 err = SSL_write(chan->ssl, (const char *)buf, len);
158 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
159 return G_IO_ERROR_AGAIN;
160 return ssl_errno(errno);
165 return G_IO_ERROR_NONE;
171 GIOError irssi_ssl_seek(GIOChannel *handle, gint offset, GSeekType type)
173 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
175 e = g_io_channel_seek(chan->giochan, offset, type);
176 return (e == G_IO_ERROR_NONE) ? G_IO_ERROR_NONE : G_IO_ERROR_INVAL;
179 void irssi_ssl_close(GIOChannel *handle)
181 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
182 g_io_channel_close(chan->giochan);
185 #if GLIB_MAJOR_VERSION < 2
186 guint irssi_ssl_create_watch(GIOChannel *handle, gint priority, GIOCondition cond,
187 GIOFunc func, gpointer data, GDestroyNotify notify)
189 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
191 return chan->giochan->funcs->io_add_watch(handle, priority, cond, func, data, notify);
194 GSource *irssi_ssl_create_watch(GIOChannel *handle, GIOCondition cond)
196 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
198 return chan->giochan->funcs->io_create_watch(handle, cond);
202 void irssi_ssl_free(GIOChannel *handle)
204 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
205 g_io_channel_unref(chan->giochan);
210 gboolean irssi_ssl_init(void)
213 SSL_load_error_strings();
215 ssl_ctx = SSL_CTX_new(SSLv23_client_method());
218 g_error("Initialization of the SSL library failed");
226 GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle)
234 g_return_val_if_fail(handle != NULL, NULL);
236 if(!ssl_ctx && !irssi_ssl_init())
239 if(!(fd = g_io_channel_unix_get_fd(handle)))
242 if(!(ssl = SSL_new(ssl_ctx)))
244 g_warning("Failed to allocate SSL structure");
248 if(!(err = SSL_set_fd(ssl, fd)))
250 g_warning("Failed to associate socket to SSL stream");
254 if((err = SSL_connect(ssl)) <= 0)
256 switch(err = SSL_get_error(ssl, err))
258 case SSL_ERROR_SYSCALL:
259 if(errno == EINTR || errno == EAGAIN)
260 case SSL_ERROR_WANT_READ:
261 case SSL_ERROR_WANT_WRITE:
267 else if(!(cert = SSL_get_peer_certificate(ssl)))
269 g_warning("SSL server supplied no certificate");
275 chan = g_new0(GIOSSLChannel, 1);
277 chan->giochan = handle;
280 g_io_channel_ref(handle);
282 gchan = (GIOChannel *)chan;
283 gchan->funcs = &irssi_ssl_channel_funcs;
284 g_io_channel_init(gchan);
289 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
291 GIOChannel *gret = net_connect_ip(ip, port, my_ip);
292 gret = irssi_ssl_get_iochannel(gret);
296 #else /* HAVE_OPENSSL */
298 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
300 g_warning("Connection failed: SSL support not enabled in this build.");
305 #endif /* ! HAVE_OPENSSL */