2
(Based on network-openssl.c from irssi)
5
Copyright (C) 2003 Jelmer Vernooij
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
#include <openssl/crypto.h>
25
#include <openssl/x509.h>
26
#include <openssl/pem.h>
27
#include <openssl/ssl.h>
28
#include <openssl/err.h>
30
/* ssl i/o channel object */
41
static void irssi_ssl_free(GIOChannel *handle)
43
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
44
g_io_channel_unref(chan->giochan);
49
static GIOStatus irssi_ssl_errno(gint e)
54
return G_IO_STATUS_ERROR;
57
return G_IO_STATUS_AGAIN;
59
return G_IO_STATUS_ERROR;
62
return G_IO_STATUS_ERROR;
65
static GIOStatus irssi_ssl_cert_step(GIOSSLChannel *chan)
68
switch(err = SSL_do_handshake(chan->ssl))
71
if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
73
g_warning("SSL server supplied no certificate");
74
return G_IO_STATUS_ERROR;
76
return G_IO_STATUS_NORMAL;
78
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
79
return G_IO_STATUS_AGAIN;
80
return irssi_ssl_errno(errno);
83
return G_IO_STATUS_ERROR;
86
static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret, GError **gerr)
88
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
91
if(chan->cert == NULL && !chan->isserver)
93
gint cert_err = irssi_ssl_cert_step(chan);
94
if(cert_err != G_IO_STATUS_NORMAL)
98
err = SSL_read(chan->ssl, buf, len);
102
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
103
return G_IO_STATUS_AGAIN;
104
return irssi_ssl_errno(errno);
107
if(err == 0) return G_IO_STATUS_EOF;
108
return G_IO_STATUS_NORMAL;
111
return G_IO_STATUS_ERROR;
114
static GIOStatus irssi_ssl_write(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
116
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
119
if(chan->cert == NULL && !chan->isserver)
121
gint cert_err = irssi_ssl_cert_step(chan);
122
if(cert_err != G_IO_STATUS_NORMAL)
126
err = SSL_write(chan->ssl, (const char *)buf, len);
130
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
131
return G_IO_STATUS_AGAIN;
132
return irssi_ssl_errno(errno);
137
return G_IO_STATUS_NORMAL;
140
return G_IO_STATUS_ERROR;
143
static GIOStatus irssi_ssl_seek(GIOChannel *handle, gint64 offset, GSeekType type, GError **gerr)
145
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
147
e = g_io_channel_seek(chan->giochan, offset, type);
148
return (e == G_IO_ERROR_NONE) ? G_IO_STATUS_NORMAL : G_IO_STATUS_ERROR;
151
static GIOStatus irssi_ssl_close(GIOChannel *handle, GError **gerr)
153
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
154
g_io_channel_close(chan->giochan);
156
return G_IO_STATUS_NORMAL;
159
static GSource *irssi_ssl_create_watch(GIOChannel *handle, GIOCondition cond)
161
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
163
return chan->giochan->funcs->io_create_watch(handle, cond);
166
static GIOStatus irssi_ssl_set_flags(GIOChannel *handle, GIOFlags flags, GError **gerr)
168
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
170
return chan->giochan->funcs->io_set_flags(handle, flags, gerr);
173
static GIOFlags irssi_ssl_get_flags(GIOChannel *handle)
175
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
177
return chan->giochan->funcs->io_get_flags(handle);
180
static GIOFuncs irssi_ssl_channel_funcs = {
185
irssi_ssl_create_watch,
191
static SSL_CTX *ssl_ctx = NULL;
193
static gboolean irssi_ssl_init(void)
196
SSL_load_error_strings();
198
ssl_ctx = SSL_CTX_new(SSLv23_method());
201
g_error("Initialization of the SSL library failed");
209
gboolean irssi_ssl_set_files(char *certf, char *keyf)
211
if(!ssl_ctx && !irssi_ssl_init())
214
if(SSL_CTX_use_certificate_file(ssl_ctx, certf, SSL_FILETYPE_PEM) <= 0) {
215
g_warning("Can't set SSL certificate file %s!", certf);
219
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, keyf, SSL_FILETYPE_PEM) <= 0) {
220
g_warning("Can't set SSL private key file %s!", keyf);
224
if(!SSL_CTX_check_private_key(ssl_ctx)) {
225
g_warning("Private key does not match the certificate public key!");
229
g_message("Using SSL certificate from %s and SSL key from %s", certf, keyf);
234
GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, gboolean server)
242
g_return_val_if_fail(handle != NULL, NULL);
244
if(!ssl_ctx && !irssi_ssl_init())
247
if(!(fd = g_io_channel_unix_get_fd(handle)))
250
if(!(ssl = SSL_new(ssl_ctx)))
252
g_warning("Failed to allocate SSL structure");
256
if(!(err = SSL_set_fd(ssl, fd)))
258
g_warning("Failed to associate socket to SSL stream");
262
if(server) err = SSL_accept(ssl);
263
else err = SSL_connect(ssl);
267
ERR_print_errors_fp(stderr);
270
else if(!(cert = SSL_get_peer_certificate(ssl)))
274
g_warning("SSL %s supplied no certificate", server?"client":"server");
281
chan = g_new0(GIOSSLChannel, 1);
283
chan->giochan = handle;
286
chan->isserver = server;
287
g_io_channel_ref(handle);
289
gchan = (GIOChannel *)chan;
290
gchan->funcs = &irssi_ssl_channel_funcs;
291
g_io_channel_init(gchan);