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>
32 /* ssl i/o channel object */
42 static void irssi_ssl_free(GIOChannel *handle)
44 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
45 g_io_channel_unref(chan->giochan);
50 #if GLIB_MAJOR_VERSION < 2
57 GIOError ssl_errno(gint e)
62 return G_IO_ERROR_INVAL;
65 return G_IO_ERROR_AGAIN;
67 return G_IO_ERROR_INVAL;
70 return G_IO_ERROR_INVAL;
73 static GIOError irssi_ssl_cert_step(GIOSSLChannel *chan)
76 switch(err = SSL_do_handshake(chan->ssl))
79 if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
81 g_warning("SSL server supplied no certificate");
82 return G_IO_ERROR_INVAL;
84 return G_IO_ERROR_NONE;
86 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
87 return G_IO_ERROR_AGAIN;
88 return ssl_errno(errno);
91 return G_IO_ERROR_INVAL;
94 static GIOError irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret)
96 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
99 if(chan->cert == NULL)
101 gint cert_err = irssi_ssl_cert_step(chan);
102 if(cert_err != G_IO_ERROR_NONE)
106 err = SSL_read(chan->ssl, buf, len);
110 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
111 return G_IO_ERROR_AGAIN;
112 return ssl_errno(errno);
117 return G_IO_ERROR_NONE;
123 static GIOError irssi_ssl_write(GIOChannel *handle, gchar *buf, guint len, guint *ret)
125 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
128 if(chan->cert == NULL)
130 gint cert_err = irssi_ssl_cert_step(chan);
131 if(cert_err != G_IO_ERROR_NONE)
136 err = SSL_write(chan->ssl, (const char *)buf, len);
140 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
141 return G_IO_ERROR_AGAIN;
142 return ssl_errno(errno);
147 return G_IO_ERROR_NONE;
150 return G_IO_ERROR_INVAL;
153 static GIOError irssi_ssl_seek(GIOChannel *handle, gint offset, GSeekType type)
155 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
157 e = g_io_channel_seek(chan->giochan, offset, type);
158 return (e == G_IO_ERROR_NONE) ? G_IO_ERROR_NONE : G_IO_ERROR_INVAL;
161 static void irssi_ssl_close(GIOChannel *handle)
163 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
164 g_io_channel_close(chan->giochan);
167 static guint irssi_ssl_create_watch(GIOChannel *handle, gint priority, GIOCondition cond,
168 GIOFunc func, gpointer data, GDestroyNotify notify)
170 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
172 return chan->giochan->funcs->io_add_watch(handle, priority, cond, func, data, notify);
175 /* ssl function pointers */
176 static GIOFuncs irssi_ssl_channel_funcs =
182 irssi_ssl_create_watch,
186 #else /* GLIB_MAJOR_VERSION < 2 */
193 GIOStatus ssl_errno(gint e)
198 return G_IO_STATUS_ERROR;
201 return G_IO_STATUS_AGAIN;
203 return G_IO_STATUS_ERROR;
206 return G_IO_STATUS_ERROR;
209 static GIOStatus irssi_ssl_cert_step(GIOSSLChannel *chan)
212 switch(err = SSL_do_handshake(chan->ssl))
215 if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
217 g_warning("SSL server supplied no certificate");
218 return G_IO_STATUS_ERROR;
220 return G_IO_STATUS_NORMAL;
222 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
223 return G_IO_STATUS_AGAIN;
224 return ssl_errno(errno);
227 return G_IO_STATUS_ERROR;
230 static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret, GError **gerr)
232 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
235 if(chan->cert == NULL)
237 gint cert_err = irssi_ssl_cert_step(chan);
238 if(cert_err != G_IO_STATUS_NORMAL)
242 err = SSL_read(chan->ssl, buf, len);
246 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
247 return G_IO_STATUS_AGAIN;
248 return ssl_errno(errno);
253 return G_IO_STATUS_NORMAL;
256 return G_IO_STATUS_ERROR;
259 static GIOStatus irssi_ssl_write(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
261 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
264 if(chan->cert == NULL)
266 gint cert_err = irssi_ssl_cert_step(chan);
267 if(cert_err != G_IO_STATUS_NORMAL)
271 err = SSL_write(chan->ssl, (const char *)buf, len);
275 if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
276 return G_IO_STATUS_AGAIN;
277 return ssl_errno(errno);
282 return G_IO_STATUS_NORMAL;
285 return G_IO_STATUS_ERROR;
288 static GIOStatus irssi_ssl_seek(GIOChannel *handle, gint64 offset, GSeekType type, GError **gerr)
290 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
292 e = g_io_channel_seek(chan->giochan, offset, type);
293 return (e == G_IO_ERROR_NONE) ? G_IO_STATUS_NORMAL : G_IO_STATUS_ERROR;
296 static GIOStatus irssi_ssl_close(GIOChannel *handle, GError **gerr)
298 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
299 g_io_channel_close(chan->giochan);
301 return G_IO_STATUS_NORMAL;
304 static GSource *irssi_ssl_create_watch(GIOChannel *handle, GIOCondition cond)
306 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
308 return chan->giochan->funcs->io_create_watch(handle, cond);
311 static GIOStatus irssi_ssl_set_flags(GIOChannel *handle, GIOFlags flags, GError **gerr)
313 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
315 return chan->giochan->funcs->io_set_flags(handle, flags, gerr);
318 static GIOFlags irssi_ssl_get_flags(GIOChannel *handle)
320 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
322 return chan->giochan->funcs->io_get_flags(handle);
325 static GIOFuncs irssi_ssl_channel_funcs = {
330 irssi_ssl_create_watch,
338 static SSL_CTX *ssl_ctx = NULL;
340 static gboolean irssi_ssl_init(void)
343 SSL_load_error_strings();
345 ssl_ctx = SSL_CTX_new(SSLv23_client_method());
348 g_error("Initialization of the SSL library failed");
356 static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle)
364 g_return_val_if_fail(handle != NULL, NULL);
366 if(!ssl_ctx && !irssi_ssl_init())
369 if(!(fd = g_io_channel_unix_get_fd(handle)))
372 if(!(ssl = SSL_new(ssl_ctx)))
374 g_warning("Failed to allocate SSL structure");
378 if(!(err = SSL_set_fd(ssl, fd)))
380 g_warning("Failed to associate socket to SSL stream");
384 if((err = SSL_connect(ssl)) <= 0)
386 switch(err = SSL_get_error(ssl, err))
388 case SSL_ERROR_SYSCALL:
389 if(errno == EINTR || errno == EAGAIN)
390 case SSL_ERROR_WANT_READ:
391 case SSL_ERROR_WANT_WRITE:
397 else if(!(cert = SSL_get_peer_certificate(ssl)))
399 g_warning("SSL server supplied no certificate");
405 chan = g_new0(GIOSSLChannel, 1);
407 chan->giochan = handle;
410 g_io_channel_ref(handle);
412 gchan = (GIOChannel *)chan;
413 gchan->funcs = &irssi_ssl_channel_funcs;
414 g_io_channel_init(gchan);
419 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
421 GIOChannel *gret = net_connect_ip(ip, port, my_ip);
422 gret = irssi_ssl_get_iochannel(gret);
426 #else /* HAVE_OPENSSL */
428 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
430 g_warning("Connection failed: SSL support not enabled in this build.");
435 #endif /* ! HAVE_OPENSSL */