This commit is contained in:
Alexander Færøy 2016-10-16 13:19:09 +00:00 committed by GitHub
commit 498b4a5a76
31 changed files with 1114 additions and 357 deletions

4
NEWS
View file

@ -17,6 +17,10 @@ v0.8.21-head 2016-xx-xx The Irssi team <staff@irssi.org>
+ autolog_ignore_targets and activity_hide_targets learn a new syntax
tag/* and * to ignore whole networks or everything.
+ /hilight got a -matchcase flag to hilight case sensitively (#421).
+ TLS: Rename SSL to TLS throughout the code and command interfaces.
+ TLS: Automatically connect using TLS for known IRC networks that supports encrypted connections.
+ TLS: OpenSSL is now a required dependency.
+ TLS: Add certificate and public key pinning support.
- IP addresses are no longer stored when resolve_reverse_lookup is
used.
- /names and $[...] now uses utf8 string operations (#40, #411).

View file

@ -153,14 +153,6 @@ AC_ARG_ENABLE(true-color,
fi,
want_truecolor=no)
dnl **
dnl ** SSL Library checks (OpenSSL)
dnl **
AC_ARG_ENABLE(ssl,
[ --disable-ssl Disable Secure Sockets Layer support],,
enable_ssl=yes)
dnl **
dnl ** just some generic stuff...
dnl **
@ -238,6 +230,11 @@ if test "x$want_socks" = "xyes"; then
])
fi
dnl **
dnl ** OpenSSL checks
dnl **
AC_CHECK_LIB([ssl], [SSL_library_init])
dnl **
dnl ** fe-text checks
dnl **
@ -279,27 +276,7 @@ if test -z "$GLIB_LIBS"; then
AC_ERROR([GLIB is required to build irssi.])
fi
LIBS="$LIBS $GLIB_LIBS"
have_openssl=no
if test "$enable_ssl" = "yes"; then
PKG_CHECK_MODULES(SSL, openssl, :, :)
if test "$SSL_LIBS"; then
CFLAGS="$CFLAGS $SSL_CFLAGS"
have_openssl=yes
else
AC_CHECK_LIB(ssl, SSL_read, [
AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h, [
SSL_LIBS="-lssl -lcrypto"
have_openssl=yes
])
],, -lcrypto)
fi
if test "$have_openssl" = "yes"; then
AC_DEFINE(HAVE_OPENSSL,, Build with OpenSSL support)
LIBS="$LIBS $SSL_LIBS"
fi
fi
LIBS="$LIBS $GLIB_LIBS -lssl -lcrypto"
dnl **
dnl ** curses checks
@ -569,12 +546,6 @@ if test "x$want_dane" = "xyes"; then
AC_DEFINE([HAVE_DANE], [], [DANE support])
have_dane=yes
], [], [-lssl -lcrypto -lsres -lpthread])
if test x$have_dane = "xyes" ; then
if test x$have_openssl = "xno" ; then
AC_ERROR([SSL is required to build Irssi with DANE support enabled.])
fi
fi
fi
if test "x$want_truecolor" = "xyes"; then
@ -695,16 +666,6 @@ echo "Install prefix ................... : $prefix"
echo
echo "Building with SSL support ........ : $have_openssl"
if test "x$have_openssl" = "xno" -a "x$enable_ssl" = "xyes"; then
if test -f /etc/debian_version; then
echo " - Try: sudo apt-get install libssl-dev"
elif test -f /etc/redhat-release; then
echo " - Try installing openssl-devel"
else
echo " - Try installing OpenSSL development headers"
fi
fi
echo "Building with 64bit DCC support .. : $offt_64bit"
echo "Building with DANE support ....... : $have_dane"
echo "Building with true color support.. : $want_truecolor"

View file

@ -5,23 +5,24 @@
%9Parameters:%9
-4: Connects using IPv4.
-6: Connects using IPv6.
-ssl: Connects using SSL encryption.
-ssl_cert: The SSL client certificate file.
-ssl_pkey: The SSL client private key, if not included in the
certificate file.
-ssl_pass: The password for the SSL client private key or certificate.
-ssl_verify: Verifies the SSL certificate of the server.
-ssl_cafile: The file with the list of CA certificates.
-ssl_capath: The directory which contains the CA certificates.
-ssl_ciphers: SSL cipher suite preference lists.
-noproxy: Ignores the global proxy configuration.
-network: The network this connection belongs to.
-host: The hostname you would like to connect from.
-rawlog: Immediately open rawlog after connecting.
-!: Doesn't autojoin channels.
-noautosendcmd: Doesn't execute autosendcmd.
-4: Connects using IPv4.
-6: Connects using IPv6.
-tls: Connects using TLS encryption.
-tls_cert: The TLS client certificate file.
-tls_pkey: The TLS client private key, if not included in the certificate file.
-tls_pass: The password for the TLS client private key or certificate.
-tls_verify: Verifies the TLS certificate of the server.
-tls_cafile: The file with the list of CA certificates.
-tls_capath: The directory which contains the CA certificates.
-tls_ciphers: TLS cipher suite preference lists.
-tls_pinned_cert: Pinned x509 certificate fingerprint.
-tls_pinned_pubkey: Pinned public key fingerprint.
-noproxy: Ignores the global proxy configuration.
-network: The network this connection belongs to.
-host: The hostname you would like to connect from.
-rawlog: Immediately open rawlog after connecting.
-!: Doesn't autojoin channels.
-noautosendcmd: Doesn't execute autosendcmd.
A network or server to connect to; you can optionally specify a custom port,
password and nickname.

View file

@ -5,45 +5,47 @@
%9Parameters:%9
LIST: Displays the list of servers you are connected to.
CONNECT: Connects to the given server.
ADD: Adds a server to your configuration.
MODIFY: Modifies a server in your configuration.
REMOVE: Removes a server from your configuration.
PURGE: Purges the commands queued to be sent to the server.
LIST: Displays the list of servers you are connected to.
CONNECT: Connects to the given server.
ADD: Adds a server to your configuration.
MODIFY: Modifies a server in your configuration.
REMOVE: Removes a server from your configuration.
PURGE: Purges the commands queued to be sent to the server.
-!: Doesn't autojoin the channels.
-4: Connects using IPv4.
-6: Connects using IPv6.
-ssl: Connects using SSL encryption.
-ssl_cert: The SSL client certificate file.
-ssl_pkey: The SSL client private key, if not included in the
certificate file.
-ssl_pass: The password for the SSL client private key or certificate.
-ssl_verify: Verifies the SSL certificate of the server.
-ssl_cafile: The file with the list of CA certificates.
-ssl_capath: The directory which contains the CA certificates.
-ssl_ciphers: SSL cipher suite preference lists.
-auto: Automatically connects to the server on startup.
-noauto: Doesn't connect to the server on startup.
-network: The network the server belongs to.
-host: The hostname you would like to connect from.
-cmdspeed: Specifies the minimum amount of time, expressed in
milliseconds, that the client must wait before sending
additional commands to the server.
-cmdmax: Specifies the maximum number of commands to perform
before starting the internal flood protection.
-port: Specifies the port to connect to the server.
-noproxy: Ignores the global proxy configuration.
-rawlog: Immediately open rawlog after connecting.
-noautosendcmd: Doesn't execute autosendcmd.
-!: Doesn't autojoin the channels.
-4: Connects using IPv4.
-6: Connects using IPv6.
-tls: Connects using TLS encryption.
-tls_cert: The TLS client certificate file.
-tls_pkey: The TLS client private key, if not included in the
certificate file.
-tls_pass: The password for the TLS client private key or certificate.
-tls_verify: Verifies the TLS certificate of the server.
-tls_cafile: The file with the list of CA certificates.
-tls_capath: The directory which contains the CA certificates.
-tls_ciphers: TLS cipher suite preference lists.
-tls_pinned_cert: Pinned x509 certificate fingerprint.
-tls_pinned_pubkey: Pinned public key fingerprint.
-auto: Automatically connects to the server on startup.
-noauto: Doesn't connect to the server on startup.
-network: The network the server belongs to.
-host: The hostname you would like to connect from.
-cmdspeed: Specifies the minimum amount of time, expressed in
milliseconds, that the client must wait before sending
additional commands to the server.
-cmdmax: Specifies the maximum number of commands to perform
before starting the internal flood protection.
-port: Specifies the port to connect to the server.
-noproxy: Ignores the global proxy configuration.
-rawlog: Immediately open rawlog after connecting.
-noautosendcmd: Doesn't execute autosendcmd.
The server, port and network to add, modify or remove; if no argument is
given, the list of servers you are connected to will be returned.
%9Description:%9
Displays, adds, modifies or removes the network configuration of IRC
Displays, adds, modifies or removes the network configuration of IRC
servers.
When using the ADD parameter on a server that already exists, the

View file

@ -59,6 +59,7 @@ network-openssl.c:
"tlsa available", SERVER_REC
"tlsa verification success", SERVER_REC
"tlsa verification failed", SERVER_REC
"tls handshake finished", SERVER_REC, TLS_REC
nicklist.c:
"nicklist new", CHANNEL_REC, NICK_REC

View file

@ -2,13 +2,13 @@ servers = (
{ address = "irc.dal.net"; chatnet = "DALnet"; port = "6667"; },
{ address = "irc.efnet.org"; chatnet = "EFNet"; port = "6667"; },
{ address = "irc.esper.net"; chatnet = "EsperNet"; port = "6667"; },
{ address = "chat.freenode.net"; chatnet = "Freenode"; port = "6667"; },
{ address = "chat.freenode.net"; chatnet = "Freenode"; port = "6697"; use_tls = "yes"; tls_verify = "yes"; },
{ address = "irc.gamesurge.net"; chatnet = "GameSurge"; port = "6667"; },
{ address = "eu.irc6.net"; chatnet = "IRCnet"; port = "6667"; },
{ address = "eu.irc6.net"; chatnet = "IRCnet"; port = "6667"; use_tls = "yes"; },
{ address = "open.ircnet.net"; chatnet = "IRCnet"; port = "6667"; },
{ address = "irc.ircsource.net"; chatnet = "IRCSource"; port = "6667"; },
{ address = "irc.netfuze.net"; chatnet = "NetFuze"; port = "6667"; },
{ address = "irc.oftc.net"; chatnet = "OFTC"; port = "6667"; },
{ address = "irc.oftc.net"; chatnet = "OFTC"; port = "6697"; use_tls = "yes"; },
{ address = "irc.quakenet.org"; chatnet = "QuakeNet"; port = "6667"; },
{ address = "irc.rizon.net"; chatnet = "Rizon"; port = "6667"; },
{ address = "silc.silcnet.org"; chatnet = "SILC"; port = "706"; },
@ -21,7 +21,7 @@ chatnets = {
max_kicks = "4";
max_msgs = "20";
max_whois = "30";
};
};
EFNet = {
type = "IRC";
max_kicks = "1";
@ -64,7 +64,7 @@ chatnets = {
max_msgs = "1";
max_whois = "1";
};
OFTC = {
OFTC = {
type = "IRC";
max_kicks = "1";
max_msgs = "1";
@ -264,7 +264,7 @@ aliases = {
statusbar = {
items = {
barstart = "{sbstart}";
barend = "{sbend}";
@ -276,10 +276,10 @@ statusbar = {
window = "{sb $winref:$tag/$itemname{sbmode $M}}";
window_empty = "{sb $winref{sbservertag $tag}}";
prompt = "{prompt $[.15]itemname}";
prompt_empty = "{prompt $winname}";
topic = " $topic";
topic_empty = " Irssi v$J - http://www.irssi.org";
@ -328,7 +328,7 @@ statusbar = {
};
prompt = {
type = "root";
placement = "bottom";
position = "100";

View file

@ -17,8 +17,8 @@ libcore_a_SOURCES = \
chatnets.c \
core.c \
expandos.c \
ignore.c \
levels.c \
ignore.c \
levels.c \
line-split.c \
log.c \
log-away.c \
@ -46,6 +46,7 @@ libcore_a_SOURCES = \
special-vars.c \
utf8.c \
wcwidth.c \
tls.c \
write-buffer.c
structure_headers = \
@ -68,8 +69,8 @@ pkginc_core_HEADERS = \
chatnets.h \
core.h \
expandos.h \
ignore.h \
levels.h \
ignore.h \
levels.h \
line-split.h \
log.h \
masks.h \
@ -97,5 +98,6 @@ pkginc_core_HEADERS = \
special-vars.h \
utf8.h \
window-item-def.h \
tls.h \
write-buffer.h \
$(structure_headers)

View file

@ -99,27 +99,31 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
else if (g_hash_table_lookup(optlist, "4") != NULL)
conn->family = AF_INET;
if (g_hash_table_lookup(optlist, "ssl") != NULL)
conn->use_ssl = TRUE;
if ((tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL)
conn->ssl_cert = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
conn->ssl_pkey = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL)
conn->ssl_pass = g_strdup(tmp);
if (g_hash_table_lookup(optlist, "ssl_verify") != NULL)
conn->ssl_verify = TRUE;
if ((tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
conn->ssl_cafile = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
conn->ssl_capath = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL)
conn->ssl_ciphers = g_strdup(tmp);
if ((conn->ssl_capath != NULL && conn->ssl_capath[0] != '\0')
|| (conn->ssl_cafile != NULL && conn->ssl_cafile[0] != '\0'))
conn->ssl_verify = TRUE;
if ((conn->ssl_cert != NULL && conn->ssl_cert[0] != '\0') || conn->ssl_verify)
conn->use_ssl = TRUE;
if (g_hash_table_lookup(optlist, "tls") != NULL || g_hash_table_lookup(optlist, "ssl") != NULL)
conn->use_tls = TRUE;
if ((tmp = g_hash_table_lookup(optlist, "tls_cert")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL)
conn->tls_cert = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_pkey")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
conn->tls_pkey = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_pass")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL)
conn->tls_pass = g_strdup(tmp);
if (g_hash_table_lookup(optlist, "tls_verify") != NULL || g_hash_table_lookup(optlist, "ssl_verify") != NULL)
conn->tls_verify = TRUE;
if ((tmp = g_hash_table_lookup(optlist, "tls_cafile")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
conn->tls_cafile = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_capath")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
conn->tls_capath = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_ciphers")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL)
conn->tls_ciphers = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_cert")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pinned_cert")) != NULL)
conn->tls_pinned_cert = g_strdup(tmp);
if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_pubkey")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pinned_pubkey")) != NULL)
conn->tls_pinned_pubkey = g_strdup(tmp);
if ((conn->tls_capath != NULL && conn->tls_capath[0] != '\0')
|| (conn->tls_cafile != NULL && conn->tls_cafile[0] != '\0'))
conn->tls_verify = TRUE;
if ((conn->tls_cert != NULL && conn->tls_cert[0] != '\0') || conn->tls_verify)
conn->use_tls = TRUE;
if (g_hash_table_lookup(optlist, "!") != NULL)
conn->no_autojoin_channels = TRUE;
@ -145,13 +149,13 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
return conn;
}
/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>] [-ssl_pass <password>]
[-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
[-ssl_ciphers <list>]
/* SYNTAX: CONNECT [-4 | -6]
[-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>] [-ssl_pass <password>]
[-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>] [-ssl_ciphers <list>]
[-!] [-noautosendcmd]
[-noproxy] [-network <network>] [-host <hostname>]
[-rawlog <file>]
<address>|<chatnet> [<port> [<password> [<nick>]]] */
[-noproxy] [-network <network>] [-host <hostname>]
[-rawlog <file>]
<address>|<chatnet> [<port> [<password> [<nick>]]] */
/* NOTE: -network replaces the old -ircnet flag. */
static void cmd_connect(const char *data)
{
@ -494,7 +498,7 @@ void chat_commands_init(void)
signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
signal_add("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +host noproxy -rawlog noautosendcmd");
command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_pinned_cert +ssl_pinned_pubkey tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey +host noproxy -rawlog noautosendcmd");
command_set_options("msg", "channel nick");
}

View file

@ -930,3 +930,23 @@ char **strsplit_len(const char *str, int len, gboolean onspace)
return ret;
}
char *binary_to_hex(unsigned char *buffer, size_t size)
{
static const char hex[] = "0123456789ABCDEF";
char *result = NULL;
int i;
if (buffer == NULL || size == 0)
return NULL;
result = g_malloc(2 * size + size);
for (i = 0; i < size; i++) {
result[i * 3 + 0] = hex[(buffer[i] >> 4) & 0xf];
result[i * 3 + 1] = hex[(buffer[i] >> 0) & 0xf];
result[i * 3 + 2] = i == size - 1 ? '\0' : ':';
}
return result;
}

View file

@ -109,4 +109,7 @@ int find_substr(const char *list, const char *item);
/* split `str' into `len' sized substrings */
char **strsplit_len(const char *str, int len, gboolean onspace);
/* Convert a given buffer to hex and return a pointer to the newly allocated hex buffer */
char *binary_to_hex(unsigned char *buffer, size_t size);
#endif

View file

@ -22,8 +22,8 @@
#include "network.h"
#include "misc.h"
#include "servers.h"
#ifdef HAVE_OPENSSL
#include "signals.h"
#include "tls.h"
#include <openssl/crypto.h>
#include <openssl/x509.h>
@ -203,9 +203,10 @@ static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname)
return matched;
}
static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, int port, X509 *cert, SERVER_REC *server)
static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, int port, X509 *cert, SERVER_REC *server, TLS_REC *tls_rec)
{
long result;
#ifdef HAVE_DANE
int dane_ret;
struct val_daneparams daneparams;
@ -242,39 +243,7 @@ static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, i
result = SSL_get_verify_result(ssl);
if (result != X509_V_OK) {
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int n;
char *str;
g_warning("Could not verify SSL servers certificate: %s",
X509_verify_cert_error_string(result));
if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL)
g_warning(" Could not get subject-name from peer certificate");
else {
g_warning(" Subject : %s", str);
free(str);
}
if ((str = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) == NULL)
g_warning(" Could not get issuer-name from peer certificate");
else {
g_warning(" Issuer : %s", str);
free(str);
}
if (! X509_digest(cert, EVP_md5(), md, &n))
g_warning(" Could not get fingerprint from peer certificate");
else {
char hex[] = "0123456789ABCDEF";
char fp[EVP_MAX_MD_SIZE*3];
if (n < sizeof(fp)) {
unsigned int i;
for (i = 0; i < n; i++) {
fp[i*3+0] = hex[(md[i] >> 4) & 0xF];
fp[i*3+1] = hex[(md[i] >> 0) & 0xF];
fp[i*3+2] = i == n - 1 ? '\0' : ':';
}
g_warning(" MD5 Fingerprint : %s", fp);
}
}
g_warning("Could not verify SSL servers certificate: %s", X509_verify_cert_error_string(result));
return FALSE;
} else if (! irssi_ssl_verify_hostname(cert, hostname)){
return FALSE;
@ -428,7 +397,6 @@ static gboolean irssi_ssl_init(void)
ssl_inited = TRUE;
return TRUE;
}
static int get_pem_password_callback(char *buffer, int max_length, int rwflag, void *pass)
@ -457,13 +425,13 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_
SSL *ssl;
SSL_CTX *ctx = NULL;
const char *mycert = server->connrec->ssl_cert;
const char *mypkey = server->connrec->ssl_pkey;
const char *mypass = server->connrec->ssl_pass;
const char *cafile = server->connrec->ssl_cafile;
const char *capath = server->connrec->ssl_capath;
const char *ciphers = server->connrec->ssl_ciphers;
gboolean verify = server->connrec->ssl_verify;
const char *mycert = server->connrec->tls_cert;
const char *mypkey = server->connrec->tls_pkey;
const char *mypass = server->connrec->tls_pass;
const char *cafile = server->connrec->tls_cafile;
const char *capath = server->connrec->tls_capath;
const char *ciphers = server->connrec->tls_ciphers;
gboolean verify = server->connrec->tls_verify;
g_return_val_if_fail(handle != NULL, NULL);
@ -482,7 +450,8 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_default_passwd_cb(ctx, get_pem_password_callback);
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)mypass);
if (ciphers && *ciphers) {
if (ciphers != NULL && ciphers[0] != '\0') {
if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1)
g_warning("No valid SSL cipher suite could be selected");
}
@ -544,8 +513,7 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_
SSL_set_tlsext_host_name(ssl, server->connrec->address);
#endif
SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
chan = g_new0(GIOSSLChannel, 1);
chan->fd = fd;
@ -565,6 +533,192 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_
return gchan;
}
static void set_cipher_info(TLS_REC *tls, SSL *ssl)
{
g_assert(tls != NULL);
g_assert(ssl != NULL);
tls_rec_set_protocol_version(tls, SSL_get_version(ssl));
tls_rec_set_cipher(tls, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
tls_rec_set_cipher_size(tls, SSL_get_cipher_bits(ssl, NULL));
}
static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_fingerprint, size_t cert_fingerprint_size, unsigned char *public_key_fingerprint, size_t public_key_fingerprint_size)
{
g_assert(tls != NULL);
g_assert(cert != NULL);
EVP_PKEY *pubkey = NULL;
char *cert_fingerprint_hex = NULL;
char *public_key_fingerprint_hex = NULL;
BIO *bio = NULL;
char buffer[128];
size_t length;
pubkey = X509_get_pubkey(cert);
cert_fingerprint_hex = binary_to_hex(cert_fingerprint, cert_fingerprint_size);
tls_rec_set_certificate_fingerprint(tls, cert_fingerprint_hex);
tls_rec_set_certificate_fingerprint_algorithm(tls, "SHA256");
// Show algorithm.
switch (EVP_PKEY_id(pubkey)) {
case EVP_PKEY_RSA:
tls_rec_set_public_key_algorithm(tls, "RSA");
break;
case EVP_PKEY_DSA:
tls_rec_set_public_key_algorithm(tls, "DSA");
break;
case EVP_PKEY_EC:
tls_rec_set_public_key_algorithm(tls, "EC");
break;
default:
tls_rec_set_public_key_algorithm(tls, "Unknown");
break;
}
public_key_fingerprint_hex = binary_to_hex(public_key_fingerprint, public_key_fingerprint_size);
tls_rec_set_public_key_fingerprint(tls, public_key_fingerprint_hex);
tls_rec_set_public_key_size(tls, EVP_PKEY_bits(pubkey));
tls_rec_set_public_key_fingerprint_algorithm(tls, "SHA256");
// Read the NotBefore timestamp.
bio = BIO_new(BIO_s_mem());
ASN1_TIME_print(bio, X509_get_notBefore(cert));
length = BIO_read(bio, buffer, sizeof(buffer));
buffer[length] = '\0';
BIO_free(bio);
tls_rec_set_not_before(tls, buffer);
// Read the NotAfter timestamp.
bio = BIO_new(BIO_s_mem());
ASN1_TIME_print(bio, X509_get_notAfter(cert));
length = BIO_read(bio, buffer, sizeof(buffer));
buffer[length] = '\0';
BIO_free(bio);
tls_rec_set_not_after(tls, buffer);
g_free(cert_fingerprint_hex);
g_free(public_key_fingerprint_hex);
EVP_PKEY_free(pubkey);
}
static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl)
{
g_assert(tls != NULL);
g_assert(ssl != NULL);
STACK_OF(X509) *chain = NULL;
int i;
chain = SSL_get_peer_cert_chain(ssl);
if (chain == NULL)
return;
for (i = 0; i < sk_X509_num(chain); i++) {
TLS_CERT_REC *cert_rec = NULL;
X509_NAME *name = NULL;
int j;
int nid;
char *key = NULL;
char *value = NULL;
cert_rec = tls_cert_create_rec();
// Subject.
name = X509_get_subject_name(sk_X509_value(chain, i));
for (j = 0; j < X509_NAME_entry_count(name); j++) {
X509_NAME_ENTRY *entry = NULL;
TLS_CERT_ENTRY_REC *tls_cert_entry_rec = NULL;
entry = X509_NAME_get_entry(name, j);
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
key = (char *)OBJ_nid2sn(nid);
if (key == NULL)
key = (char *)OBJ_nid2ln(nid);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(entry);
value = (char *)ASN1_STRING_data(d);
tls_cert_entry_rec = tls_cert_entry_create_rec(key, value);
tls_cert_rec_append_subject_entry(cert_rec, tls_cert_entry_rec);
}
// Issuer.
name = X509_get_issuer_name(sk_X509_value(chain, i));
for (j = 0; j < X509_NAME_entry_count(name); j++) {
X509_NAME_ENTRY *entry = NULL;
TLS_CERT_ENTRY_REC *tls_cert_entry_rec = NULL;
entry = X509_NAME_get_entry(name, j);
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
key = (char *)OBJ_nid2sn(nid);
if (key == NULL)
key = (char *)OBJ_nid2ln(nid);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(entry);
value = (char *)ASN1_STRING_data(d);
tls_cert_entry_rec = tls_cert_entry_create_rec(key, value);
tls_cert_rec_append_issuer_entry(cert_rec, tls_cert_entry_rec);
}
tls_rec_append_cert(tls, cert_rec);
}
}
static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl)
{
g_assert(tls != NULL);
g_assert(ssl != NULL);
#ifdef SSL_get_server_tmp_key
// Show ephemeral key information.
EVP_PKEY *ephemeral_key = NULL;
if (SSL_get_server_tmp_key(ssl, &ephemeral_key)) {
switch (EVP_PKEY_id(ephemeral_key)) {
case EVP_PKEY_DH:
tls_rec_set_ephemeral_key_algorithm(tls, "DH");
tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key));
break;
case EVP_PKEY_EC:
{
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(ephemeral_key);
int nid;
const char *cname;
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
EC_KEY_free(ec);
cname = OBJ_nid2sn(nid);
char *ephemeral_key_algorithm = g_strdup_printf("ECDH: %s", cname);
tls_rec_set_ephemeral_key_algorithm(tls, ephemeral_key_algorithm);
tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key));
g_free_and_null(ephemeral_key_algorithm);
}
}
EVP_PKEY_free(ephemeral_key);
}
#endif // SSL_get_server_tmp_key.
}
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server)
{
GIOChannel *handle, *ssl_handle;
@ -582,8 +736,19 @@ int irssi_ssl_handshake(GIOChannel *handle)
{
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
int ret, err;
X509 *cert;
const char *errstr;
const char *errstr = NULL;
X509 *cert = NULL;
X509_PUBKEY *pubkey = NULL;
int pubkey_size = 0;
unsigned char *pubkey_der = NULL;
unsigned char *pubkey_der_tmp = NULL;
unsigned char pubkey_fingerprint[EVP_MAX_MD_SIZE];
unsigned int pubkey_fingerprint_size;
unsigned char cert_fingerprint[EVP_MAX_MD_SIZE];
unsigned int cert_fingerprint_size;
const char *pinned_cert_fingerprint = chan->server->connrec->tls_pinned_cert;
const char *pinned_pubkey_fingerprint = chan->server->connrec->tls_pinned_pubkey;
TLS_REC *tls = NULL;
ERR_clear_error();
ret = SSL_connect(chan->ssl);
@ -611,22 +776,73 @@ int irssi_ssl_handshake(GIOChannel *handle)
}
cert = SSL_get_peer_certificate(chan->ssl);
pubkey = X509_get_X509_PUBKEY(cert);
if (cert == NULL) {
g_warning("SSL server supplied no certificate");
return -1;
}
ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server);
if (pubkey == NULL) {
g_warning("SSL server supplied no certificate public key");
return -1;
}
if (! X509_digest(cert, EVP_sha256(), cert_fingerprint, &cert_fingerprint_size)) {
g_warning("Unable to generate certificate fingerprint");
X509_free(cert);
return -1;
}
pubkey_size = i2d_X509_PUBKEY(pubkey, NULL);
pubkey_der = pubkey_der_tmp = g_new(unsigned char, pubkey_size);
i2d_X509_PUBKEY(pubkey, &pubkey_der_tmp);
EVP_Digest(pubkey_der, pubkey_size, pubkey_fingerprint, &pubkey_fingerprint_size, EVP_sha256(), 0);
tls = tls_create_rec();
set_cipher_info(tls, chan->ssl);
set_pubkey_info(tls, cert, cert_fingerprint, cert_fingerprint_size, pubkey_fingerprint, pubkey_fingerprint_size);
set_peer_cert_chain_info(tls, chan->ssl);
set_server_temporary_key_info(tls, chan->ssl);
ret = 1;
do {
if (pinned_cert_fingerprint != NULL && pinned_cert_fingerprint[0] != '\0') {
ret = g_ascii_strcasecmp(pinned_cert_fingerprint, tls->certificate_fingerprint) == 0;
if (! ret) {
g_warning(" Pinned certificate mismatch");
continue;
}
}
if (pinned_pubkey_fingerprint != NULL && pinned_pubkey_fingerprint[0] != '\0') {
ret = g_ascii_strcasecmp(pinned_pubkey_fingerprint, tls->public_key_fingerprint) == 0;
if (! ret) {
g_warning(" Pinned public key mismatch");
continue;
}
}
if (chan->verify) {
ret = irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server, tls);
if (! ret) {
// irssi_ssl_verify emits a warning itself.
continue;
}
}
} while (0);
// Emit the TLS rec.
signal_emit("tls handshake finished", 2, chan->server, tls);
tls_rec_free(tls);
X509_free(cert);
g_free(pubkey_der);
return ret ? 0 : -1;
}
#else /* HAVE_OPENSSL */
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server)
{
g_warning("Connection failed: SSL support not enabled in this build.");
errno = ENOSYS;
return NULL;
}
#endif /* ! HAVE_OPENSSL */

View file

@ -23,12 +23,14 @@ char *nick;
char *username;
char *realname;
char *ssl_cert;
char *ssl_pkey;
char *ssl_pass;
char *ssl_cafile;
char *ssl_capath;
char *ssl_ciphers;
char *tls_cert;
char *tls_pkey;
char *tls_pass;
char *tls_cafile;
char *tls_capath;
char *tls_ciphers;
char *tls_pinned_cert;
char *tls_pinned_pubkey;
GIOChannel *connect_handle; /* connect using this handle */
@ -38,8 +40,8 @@ unsigned int reconnecting:1; /* we're trying to reconnect any connection */
unsigned int no_autojoin_channels:1; /* don't autojoin any channels */
unsigned int no_autosendcmd:1; /* don't execute autosendcmd */
unsigned int unix_socket:1; /* Connect using named unix socket */
unsigned int use_ssl:1; /* this connection uses SSL */
unsigned int ssl_verify:1;
unsigned int use_tls:1; /* this connection uses TLS */
unsigned int tls_verify:1;
unsigned int no_connect:1; /* don't connect() at all, it's done by plugin */
char *channels;
char *away_reason;

View file

@ -59,11 +59,9 @@ int (*ischannel)(SERVER_REC *server, const char *data);
of them aren't supported '\0' can be used. */
const char *(*get_nick_flags)(SERVER_REC *server);
/* send public or private message to server */
void (*send_message)(SERVER_REC *server, const char *target,
const char *msg, int target_type);
void (*send_message)(SERVER_REC *server, const char *target, const char *msg, int target_type);
/* split message in case it is too long for the server to receive */
char **(*split_message)(SERVER_REC *server, const char *target,
const char *msg);
char **(*split_message)(SERVER_REC *server, const char *target, const char *msg);
/* -- Default implementations are used if NULL -- */
CHANNEL_REC *(*channel_find_func)(SERVER_REC *server, const char *name);

View file

@ -11,12 +11,14 @@ char *password;
int sasl_mechanism;
char *sasl_password;
char *ssl_cert;
char *ssl_pkey;
char *ssl_pass;
char *ssl_cafile;
char *ssl_capath;
char *ssl_ciphers;
char *tls_cert;
char *tls_pkey;
char *tls_pass;
char *tls_cafile;
char *tls_capath;
char *tls_ciphers;
char *tls_pinned_cert;
char *tls_pinned_pubkey;
char *own_host; /* address to use when connecting this server */
IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */
@ -28,7 +30,7 @@ unsigned int no_proxy:1;
unsigned int last_failed:1; /* if last connection attempt failed */
unsigned int banned:1; /* if we're banned from this server */
unsigned int dns_error:1; /* DNS said the host doesn't exist */
unsigned int use_ssl:1; /* this connection uses SSL */
unsigned int ssl_verify:1;
unsigned int use_tls:1; /* this connection uses TLS */
unsigned int tls_verify:1;
GHashTable *module_data;

View file

@ -192,13 +192,15 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
dest->no_autosendcmd = src->no_autosendcmd;
dest->unix_socket = src->unix_socket;
dest->use_ssl = src->use_ssl;
dest->ssl_cert = g_strdup(src->ssl_cert);
dest->ssl_pkey = g_strdup(src->ssl_pkey);
dest->ssl_verify = src->ssl_verify;
dest->ssl_cafile = g_strdup(src->ssl_cafile);
dest->ssl_capath = g_strdup(src->ssl_capath);
dest->ssl_ciphers = g_strdup(src->ssl_ciphers);
dest->use_tls = src->use_tls;
dest->tls_cert = g_strdup(src->tls_cert);
dest->tls_pkey = g_strdup(src->tls_pkey);
dest->tls_verify = src->tls_verify;
dest->tls_cafile = g_strdup(src->tls_cafile);
dest->tls_capath = g_strdup(src->tls_capath);
dest->tls_ciphers = g_strdup(src->tls_ciphers);
dest->tls_pinned_cert = g_strdup(src->tls_pinned_cert);
dest->tls_pinned_pubkey = g_strdup(src->tls_pinned_pubkey);
return dest;
}

View file

@ -167,20 +167,24 @@ static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
if (sserver->port > 0 && conn->port <= 0)
conn->port = sserver->port;
conn->use_ssl = sserver->use_ssl;
if (conn->ssl_cert == NULL && sserver->ssl_cert != NULL && sserver->ssl_cert[0] != '\0')
conn->ssl_cert = g_strdup(sserver->ssl_cert);
if (conn->ssl_pkey == NULL && sserver->ssl_pkey != NULL && sserver->ssl_pkey[0] != '\0')
conn->ssl_pkey = g_strdup(sserver->ssl_pkey);
if (conn->ssl_pass == NULL && sserver->ssl_pass != NULL && sserver->ssl_pass[0] != '\0')
conn->ssl_pass = g_strdup(sserver->ssl_pass);
conn->ssl_verify = sserver->ssl_verify;
if (conn->ssl_cafile == NULL && sserver->ssl_cafile != NULL && sserver->ssl_cafile[0] != '\0')
conn->ssl_cafile = g_strdup(sserver->ssl_cafile);
if (conn->ssl_capath == NULL && sserver->ssl_capath != NULL && sserver->ssl_capath[0] != '\0')
conn->ssl_capath = g_strdup(sserver->ssl_capath);
if (conn->ssl_ciphers == NULL && sserver->ssl_ciphers != NULL && sserver->ssl_ciphers[0] != '\0')
conn->ssl_ciphers = g_strdup(sserver->ssl_ciphers);
conn->use_tls = sserver->use_tls;
if (conn->tls_cert == NULL && sserver->tls_cert != NULL && sserver->tls_cert[0] != '\0')
conn->tls_cert = g_strdup(sserver->tls_cert);
if (conn->tls_pkey == NULL && sserver->tls_pkey != NULL && sserver->tls_pkey[0] != '\0')
conn->tls_pkey = g_strdup(sserver->tls_pkey);
if (conn->tls_pass == NULL && sserver->tls_pass != NULL && sserver->tls_pass[0] != '\0')
conn->tls_pass = g_strdup(sserver->tls_pass);
conn->tls_verify = sserver->tls_verify;
if (conn->tls_cafile == NULL && sserver->tls_cafile != NULL && sserver->tls_cafile[0] != '\0')
conn->tls_cafile = g_strdup(sserver->tls_cafile);
if (conn->tls_capath == NULL && sserver->tls_capath != NULL && sserver->tls_capath[0] != '\0')
conn->tls_capath = g_strdup(sserver->tls_capath);
if (conn->tls_ciphers == NULL && sserver->tls_ciphers != NULL && sserver->tls_ciphers[0] != '\0')
conn->tls_ciphers = g_strdup(sserver->tls_ciphers);
if (conn->tls_pinned_cert == NULL && sserver->tls_pinned_cert != NULL && sserver->tls_pinned_cert[0] != '\0')
conn->tls_pinned_cert = g_strdup(sserver->tls_pinned_cert);
if (conn->tls_pinned_pubkey == NULL && sserver->tls_pinned_pubkey != NULL && sserver->tls_pinned_pubkey[0] != '\0')
conn->tls_pinned_pubkey = g_strdup(sserver->tls_pinned_pubkey);
server_setup_fill_reconn(conn, sserver);
@ -362,9 +366,10 @@ SERVER_SETUP_REC *server_setup_find(const char *address, int port,
static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
{
SERVER_SETUP_REC *rec;
CHATNET_REC *chatnetrec;
CHATNET_REC *chatnetrec;
char *server, *chatnet, *family;
int port;
char *value = NULL;
g_return_val_if_fail(node != NULL, NULL);
@ -390,7 +395,7 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
chatnet_create(chatnetrec);
}
family = config_node_get_str(node, "family", "");
family = config_node_get_str(node, "family", "");
rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup();
rec->type = module_get_uniq_id("SERVER SETUP", 0);
@ -400,18 +405,55 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
(g_ascii_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
rec->address = g_strdup(server);
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE);
rec->ssl_cert = g_strdup(config_node_get_str(node, "ssl_cert", NULL));
rec->ssl_pkey = g_strdup(config_node_get_str(node, "ssl_pkey", NULL));
rec->ssl_pass = g_strdup(config_node_get_str(node, "ssl_pass", NULL));
rec->ssl_verify = config_node_get_bool(node, "ssl_verify", FALSE);
rec->ssl_cafile = g_strdup(config_node_get_str(node, "ssl_cafile", NULL));
rec->ssl_capath = g_strdup(config_node_get_str(node, "ssl_capath", NULL));
rec->ssl_ciphers = g_strdup(config_node_get_str(node, "ssl_ciphers", NULL));
if (rec->ssl_cafile || rec->ssl_capath)
rec->ssl_verify = TRUE;
if (rec->ssl_cert != NULL || rec->ssl_verify)
rec->use_ssl = TRUE;
rec->use_tls = config_node_get_bool(node, "use_tls", FALSE) || config_node_get_bool(node, "use_ssl", FALSE);
rec->tls_verify = config_node_get_bool(node, "tls_verify", FALSE) || config_node_get_bool(node, "ssl_verify", FALSE);
value = config_node_get_str(node, "tls_cert", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_cert", NULL);
rec->tls_cert = g_strdup(value);
value = config_node_get_str(node, "tls_pkey", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_pkey", NULL);
rec->tls_pkey = g_strdup(value);
value = config_node_get_str(node, "tls_pass", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_pass", NULL);
rec->tls_pass = g_strdup(value);
value = config_node_get_str(node, "tls_cafile", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_cafile", NULL);
rec->tls_cafile = g_strdup(value);
value = config_node_get_str(node, "tls_capath", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_capath", NULL);
rec->tls_capath = g_strdup(value);
value = config_node_get_str(node, "tls_ciphers", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_ciphers", NULL);
rec->tls_ciphers = g_strdup(value);
value = config_node_get_str(node, "tls_pinned_cert", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_pinned_cert", NULL);
rec->tls_pinned_cert = g_strdup(value);
value = config_node_get_str(node, "tls_pinned_pubkey", NULL);
if (value == NULL)
value = config_node_get_str(node, "ssl_pinned_pubkey", NULL);
rec->tls_pinned_pubkey = g_strdup(value);
if (rec->tls_cafile || rec->tls_capath)
rec->tls_verify = TRUE;
if (rec->tls_cert != NULL || rec->tls_verify)
rec->use_tls = TRUE;
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
@ -463,14 +505,18 @@ static void server_setup_save(SERVER_SETUP_REC *rec)
iconfig_node_set_int(node, "port", rec->port);
iconfig_node_set_str(node, "password", rec->password);
iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
iconfig_node_set_str(node, "ssl_cert", rec->ssl_cert);
iconfig_node_set_str(node, "ssl_pkey", rec->ssl_pkey);
iconfig_node_set_str(node, "ssl_pass", rec->ssl_pass);
iconfig_node_set_bool(node, "ssl_verify", rec->ssl_verify);
iconfig_node_set_str(node, "ssl_cafile", rec->ssl_cafile);
iconfig_node_set_str(node, "ssl_capath", rec->ssl_capath);
iconfig_node_set_str(node, "ssl_ciphers", rec->ssl_ciphers);
iconfig_node_set_bool(node, "use_tls", rec->use_tls);
iconfig_node_set_str(node, "tls_cert", rec->tls_cert);
iconfig_node_set_str(node, "tls_pkey", rec->tls_pkey);
iconfig_node_set_str(node, "tls_pass", rec->tls_pass);
iconfig_node_set_bool(node, "tls_verify", rec->tls_verify);
iconfig_node_set_str(node, "tls_cafile", rec->tls_cafile);
iconfig_node_set_str(node, "tls_capath", rec->tls_capath);
iconfig_node_set_str(node, "tls_ciphers", rec->tls_ciphers);
iconfig_node_set_str(node, "tls_pinned_cert", rec->tls_pinned_cert);
iconfig_node_set_str(node, "tls_pinned_pubkey", rec->tls_pinned_pubkey);
iconfig_node_set_str(node, "own_host", rec->own_host);
iconfig_node_set_str(node, "family",
@ -514,12 +560,14 @@ static void server_setup_destroy(SERVER_SETUP_REC *rec)
g_free_not_null(rec->own_ip6);
g_free_not_null(rec->chatnet);
g_free_not_null(rec->password);
g_free_not_null(rec->ssl_cert);
g_free_not_null(rec->ssl_pkey);
g_free_not_null(rec->ssl_pass);
g_free_not_null(rec->ssl_cafile);
g_free_not_null(rec->ssl_capath);
g_free_not_null(rec->ssl_ciphers);
g_free_not_null(rec->tls_cert);
g_free_not_null(rec->tls_pkey);
g_free_not_null(rec->tls_pass);
g_free_not_null(rec->tls_cafile);
g_free_not_null(rec->tls_capath);
g_free_not_null(rec->tls_ciphers);
g_free_not_null(rec->tls_pinned_cert);
g_free_not_null(rec->tls_pinned_pubkey);
g_free(rec->address);
g_free(rec);
}

View file

@ -167,7 +167,6 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle)
server_connect_finished(server);
}
#ifdef HAVE_OPENSSL
static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *handle)
{
int error;
@ -198,7 +197,6 @@ static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *han
server_connect_finished(server);
}
#endif
static void server_real_connect(SERVER_REC *server, IPADDR *ip,
const char *unix_socket)
@ -221,7 +219,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
own_ip = IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : server->connrec->own_ip4;
port = server->connrec->proxy != NULL ?
server->connrec->proxy_port : server->connrec->port;
handle = server->connrec->use_ssl ?
handle = server->connrec->use_tls ?
net_connect_ip_ssl(ip, port, own_ip, server) : net_connect_ip(ip, port, own_ip);
} else {
handle = net_connect_unix(unix_socket);
@ -239,7 +237,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
}
server->no_reconnect = TRUE;
}
if (server->connrec->use_ssl && errno == ENOSYS)
if (server->connrec->use_tls && errno == ENOSYS)
server->no_reconnect = TRUE;
server->connection_lost = TRUE;
@ -247,11 +245,9 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
g_free(errmsg2);
} else {
server->handle = net_sendbuffer_create(handle, 0);
#ifdef HAVE_OPENSSL
if (server->connrec->use_ssl)
if (server->connrec->use_tls)
server_connect_callback_init_ssl(server, handle);
else
#endif
server->connect_tag =
g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ,
(GInputFunction)
@ -626,22 +622,24 @@ void server_connect_unref(SERVER_CONNECT_REC *conn)
g_free_not_null(conn->own_ip4);
g_free_not_null(conn->own_ip6);
g_free_not_null(conn->password);
g_free_not_null(conn->nick);
g_free_not_null(conn->username);
g_free_not_null(conn->password);
g_free_not_null(conn->nick);
g_free_not_null(conn->username);
g_free_not_null(conn->realname);
g_free_not_null(conn->ssl_cert);
g_free_not_null(conn->ssl_pkey);
g_free_not_null(conn->ssl_pass);
g_free_not_null(conn->ssl_cafile);
g_free_not_null(conn->ssl_capath);
g_free_not_null(conn->ssl_ciphers);
g_free_not_null(conn->tls_cert);
g_free_not_null(conn->tls_pkey);
g_free_not_null(conn->tls_pass);
g_free_not_null(conn->tls_cafile);
g_free_not_null(conn->tls_capath);
g_free_not_null(conn->tls_ciphers);
g_free_not_null(conn->tls_pinned_cert);
g_free_not_null(conn->tls_pinned_pubkey);
g_free_not_null(conn->channels);
g_free_not_null(conn->away_reason);
g_free_not_null(conn->away_reason);
conn->type = 0;
conn->type = 0;
g_free(conn);
}

View file

@ -150,8 +150,7 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config,
node = config_node_section(config, node, NULL, NODE_TYPE_BLOCK);
config_node_set_str(config, node, "chat_type",
chat_protocol_find_id(server->chat_type)->name);
config_node_set_str(config, node, "chat_type", chat_protocol_find_id(server->chat_type)->name);
config_node_set_str(config, node, "address", server->connrec->address);
config_node_set_int(config, node, "port", server->connrec->port);
config_node_set_str(config, node, "chatnet", server->connrec->chatnet);
@ -159,13 +158,15 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config,
config_node_set_str(config, node, "nick", server->nick);
config_node_set_str(config, node, "version", server->version);
config_node_set_bool(config, node, "use_ssl", server->connrec->use_ssl);
config_node_set_str(config, node, "ssl_cert", server->connrec->ssl_cert);
config_node_set_str(config, node, "ssl_pkey", server->connrec->ssl_pkey);
config_node_set_bool(config, node, "ssl_verify", server->connrec->ssl_verify);
config_node_set_str(config, node, "ssl_cafile", server->connrec->ssl_cafile);
config_node_set_str(config, node, "ssl_capath", server->connrec->ssl_capath);
config_node_set_str(config, node, "ssl_ciphers", server->connrec->ssl_ciphers);
config_node_set_bool(config, node, "use_tls", server->connrec->use_tls);
config_node_set_str(config, node, "tls_cert", server->connrec->tls_cert);
config_node_set_str(config, node, "tls_pkey", server->connrec->tls_pkey);
config_node_set_bool(config, node, "tls_verify", server->connrec->tls_verify);
config_node_set_str(config, node, "tls_cafile", server->connrec->tls_cafile);
config_node_set_str(config, node, "tls_capath", server->connrec->tls_capath);
config_node_set_str(config, node, "tls_ciphers", server->connrec->tls_ciphers);
config_node_set_str(config, node, "tls_pinned_cert", server->connrec->tls_pinned_cert);
config_node_set_str(config, node, "tls_pinned_pubkey", server->connrec->tls_pinned_pubkey);
handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
config_node_set_int(config, node, "handle", handle);

219
src/core/tls.c Normal file
View file

@ -0,0 +1,219 @@
/*
* Copyright (c) 2015 Alexander Færøy <ahf@irssi.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
*/
#include "module.h"
#include "tls.h"
TLS_REC *tls_create_rec()
{
TLS_REC *rec = g_new0(TLS_REC, 1);
g_assert(rec != NULL);
return rec;
}
void tls_rec_free(TLS_REC *tls_rec)
{
if (tls_rec == NULL)
return;
g_free_and_null(tls_rec->protocol_version);
g_free_and_null(tls_rec->cipher);
g_free_and_null(tls_rec->public_key_algorithm);
g_free_and_null(tls_rec->public_key_fingerprint);
g_free_and_null(tls_rec->public_key_fingerprint_algorithm);
g_free_and_null(tls_rec->certificate_fingerprint);
g_free_and_null(tls_rec->certificate_fingerprint_algorithm);
g_free_and_null(tls_rec->not_after);
g_free_and_null(tls_rec->not_before);
#ifdef SSL_get_server_tmp_key
g_free_and_null(tls_rec->ephemeral_key_algorithm);
#endif
if (tls_rec->certs != NULL) {
g_slist_foreach(tls_rec->certs, (GFunc)tls_cert_rec_free, NULL);
g_slist_free(tls_rec->certs);
tls_rec->certs = NULL;
}
g_free(tls_rec);
}
void tls_rec_set_protocol_version(TLS_REC *tls_rec, const char *protocol_version)
{
g_assert(tls_rec != NULL);
tls_rec->protocol_version = g_strdup(protocol_version);
}
void tls_rec_set_cipher(TLS_REC *tls_rec, const char *cipher)
{
g_assert(tls_rec != NULL);
tls_rec->cipher = g_strdup(cipher);
}
void tls_rec_set_cipher_size(TLS_REC *tls_rec, size_t size)
{
g_assert(tls_rec != NULL);
tls_rec->cipher_size = size;
}
void tls_rec_set_public_key_algorithm(TLS_REC *tls_rec, const char *algorithm)
{
g_assert(tls_rec != NULL);
tls_rec->public_key_algorithm = g_strdup(algorithm);
}
void tls_rec_set_public_key_fingerprint(TLS_REC *tls_rec, const char *fingerprint)
{
g_assert(tls_rec != NULL);
tls_rec->public_key_fingerprint = g_strdup(fingerprint);
}
void tls_rec_set_public_key_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm)
{
g_assert(tls_rec != NULL);
tls_rec->public_key_fingerprint_algorithm = g_strdup(algorithm);
}
void tls_rec_set_public_key_size(TLS_REC *tls_rec, size_t size)
{
g_assert(tls_rec != NULL);
tls_rec->public_key_size = size;
}
void tls_rec_set_certificate_fingerprint(TLS_REC *tls_rec, const char *fingerprint)
{
g_assert(tls_rec != NULL);
tls_rec->certificate_fingerprint = g_strdup(fingerprint);
}
void tls_rec_set_certificate_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm)
{
g_assert(tls_rec != NULL);
tls_rec->certificate_fingerprint_algorithm = g_strdup(algorithm);
}
void tls_rec_set_not_after(TLS_REC *tls_rec, const char *not_after)
{
g_assert(tls_rec != NULL);
tls_rec->not_after = g_strdup(not_after);
}
void tls_rec_set_not_before(TLS_REC *tls_rec, const char *not_before)
{
g_assert(tls_rec != NULL);
tls_rec->not_before = g_strdup(not_before);
}
#ifdef SSL_get_server_tmp_key
void tls_rec_set_ephemeral_key_algorithm(TLS_REC *tls_rec, const char *algorithm)
{
g_assert(tls_rec != NULL);
tls_rec->ephemeral_key_algorithm = g_strdup(algorithm);
}
void tls_rec_set_ephemeral_key_size(TLS_REC *tls_rec, size_t size)
{
g_assert(tls_rec != NULL);
tls_rec->ephemeral_key_size = size;
}
#endif
void tls_rec_append_cert(TLS_REC *tls_rec, TLS_CERT_REC *tls_cert_rec)
{
g_assert(tls_rec != NULL);
g_assert(tls_cert_rec != NULL);
tls_rec->certs = g_slist_append(tls_rec->certs, tls_cert_rec);
}
TLS_CERT_REC *tls_cert_create_rec()
{
TLS_CERT_REC *rec = g_new0(TLS_CERT_REC, 1);
g_assert(rec != NULL);
return rec;
}
void tls_cert_rec_append_subject_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec)
{
g_assert(tls_cert_rec != NULL);
g_assert(tls_cert_entry_rec != NULL);
tls_cert_rec->subject = g_slist_append(tls_cert_rec->subject, tls_cert_entry_rec);
}
void tls_cert_rec_append_issuer_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec)
{
g_assert(tls_cert_rec != NULL);
g_assert(tls_cert_entry_rec != NULL);
tls_cert_rec->issuer = g_slist_append(tls_cert_rec->issuer, tls_cert_entry_rec);
}
void tls_cert_rec_free(TLS_CERT_REC *tls_cert_rec)
{
if (tls_cert_rec == NULL)
return;
if (tls_cert_rec->subject != NULL) {
g_slist_foreach(tls_cert_rec->subject, (GFunc)tls_cert_entry_rec_free, NULL);
g_slist_free(tls_cert_rec->subject);
tls_cert_rec->subject = NULL;
}
if (tls_cert_rec->issuer != NULL) {
g_slist_foreach(tls_cert_rec->issuer, (GFunc)tls_cert_entry_rec_free, NULL);
g_slist_free(tls_cert_rec->issuer);
tls_cert_rec->issuer = NULL;
}
g_free(tls_cert_rec);
}
TLS_CERT_ENTRY_REC *tls_cert_entry_create_rec(const char *name, const char *value)
{
TLS_CERT_ENTRY_REC *rec = g_new0(TLS_CERT_ENTRY_REC, 1);
g_assert(rec != NULL);
rec->name = g_strdup(name);
rec->value = g_strdup(value);
return rec;
}
void tls_cert_entry_rec_free(TLS_CERT_ENTRY_REC *tls_cert_entry)
{
if (tls_cert_entry == NULL)
return;
g_free_and_null(tls_cert_entry->name);
g_free_and_null(tls_cert_entry->value);
g_free(tls_cert_entry);
}

98
src/core/tls.h Normal file
View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2015 Alexander Færøy <ahf@irssi.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
*/
#ifndef __TLS_H
#define __TLS_H
#include <openssl/ssl.h>
#include <stdbool.h>
typedef struct _TLS_REC TLS_REC;
typedef struct _TLS_CERT_REC TLS_CERT_REC;
typedef struct _TLS_CERT_ENTRY_REC TLS_CERT_ENTRY_REC;
struct _TLS_REC {
char *protocol_version;
char *cipher;
size_t cipher_size;
char *public_key_algorithm;
char *public_key_fingerprint;
char *public_key_fingerprint_algorithm;
size_t public_key_size;
char *certificate_fingerprint;
char *certificate_fingerprint_algorithm;
char *not_after;
char *not_before;
#ifdef SSL_get_server_tmp_key
char *ephemeral_key_algorithm;
size_t ephemeral_key_size;
#endif
GSList *certs;
bool success;
char *error;
};
struct _TLS_CERT_REC {
GSList *subject;
GSList *issuer;
};
struct _TLS_CERT_ENTRY_REC {
char *name;
char *value;
};
TLS_REC *tls_create_rec();
void tls_rec_free(TLS_REC *tls_rec);
void tls_rec_set_protocol_version(TLS_REC *tls_rec, const char *protocol_version);
void tls_rec_set_cipher(TLS_REC *tls_rec, const char *cipher);
void tls_rec_set_cipher_size(TLS_REC *tls_rec, size_t size);
void tls_rec_set_public_key_algorithm(TLS_REC *tls_rec, const char *algorithm);
void tls_rec_set_public_key_fingerprint(TLS_REC *tls_rec, const char *fingerprint);
void tls_rec_set_public_key_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm);
void tls_rec_set_public_key_size(TLS_REC *tls_rec, size_t size);
void tls_rec_set_certificate_fingerprint(TLS_REC *tls_rec, const char *fingerprint);
void tls_rec_set_certificate_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm);
void tls_rec_set_not_after(TLS_REC *tls_rec, const char *not_after);
void tls_rec_set_not_before(TLS_REC *tls_rec, const char *not_before);
#ifdef SSL_get_server_tmp_key
void tls_rec_set_ephemeral_key_algorithm(TLS_REC *tls_rec, const char *algorithm);
void tls_rec_set_ephemeral_key_size(TLS_REC *tls_rec, size_t size);
#endif
void tls_rec_append_cert(TLS_REC *tls_rec, TLS_CERT_REC *tls_cert_rec);
TLS_CERT_REC *tls_cert_create_rec();
void tls_cert_rec_free(TLS_CERT_REC *tls_cert_rec);
void tls_cert_rec_append_subject_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec);
void tls_cert_rec_append_issuer_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec);
TLS_CERT_ENTRY_REC *tls_cert_entry_create_rec(const char *name, const char *value);
void tls_cert_entry_rec_free(TLS_CERT_ENTRY_REC *tls_cert_entry);
#endif

View file

@ -24,6 +24,7 @@ libfe_common_core_a_SOURCES = \
fe-queries.c \
fe-server.c \
fe-settings.c \
fe-tls.c \
formats.c \
hilight-text.c \
keyboard.c \
@ -48,6 +49,7 @@ pkginc_fe_common_core_HEADERS = \
fe-exec.h \
fe-messages.h \
fe-queries.h \
fe-tls.h \
formats.h \
hilight-text.h \
keyboard.h \

View file

@ -88,6 +88,9 @@ void fe_server_deinit(void);
void fe_settings_init(void);
void fe_settings_deinit(void);
void fe_tls_init(void);
void fe_tls_deinit(void);
void window_commands_init(void);
void window_commands_deinit(void);
@ -161,21 +164,24 @@ void fe_common_core_init(void)
g_get_charset(&str);
settings_add_str("lookandfeel", "term_charset", str);
themes_init();
theme_register(fecommon_core_formats);
theme_register(fecommon_core_formats);
command_history_init();
completion_init();
keyboard_init();
printtext_init();
formats_init();
fe_exec_init();
fe_expandos_init();
#ifndef WIN32
fe_exec_init();
#endif
fe_expandos_init();
fe_help_init();
fe_ignore_init();
fe_log_init();
fe_modules_init();
fe_server_init();
fe_settings_init();
fe_tls_init();
windows_init();
window_activity_init();
window_commands_init();
@ -183,8 +189,8 @@ void fe_common_core_init(void)
windows_layout_init();
fe_core_commands_init();
fe_channels_init();
fe_queries_init();
fe_channels_init();
fe_queries_init();
fe_messages_init();
hilight_text_init();
@ -193,10 +199,10 @@ void fe_common_core_init(void)
settings_check();
signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_add_last("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_add_last("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
module_register("core", "fe");
}
@ -209,14 +215,17 @@ void fe_common_core_deinit(void)
keyboard_deinit();
printtext_deinit();
formats_deinit();
fe_exec_deinit();
fe_expandos_deinit();
#ifndef WIN32
fe_exec_deinit();
#endif
fe_expandos_deinit();
fe_help_deinit();
fe_ignore_deinit();
fe_log_deinit();
fe_modules_deinit();
fe_server_deinit();
fe_settings_deinit();
fe_tls_deinit();
windows_deinit();
window_activity_deinit();
window_commands_deinit();
@ -224,21 +233,21 @@ void fe_common_core_deinit(void)
windows_layout_deinit();
fe_core_commands_deinit();
fe_channels_deinit();
fe_queries_deinit();
fe_channels_deinit();
fe_queries_deinit();
fe_messages_deinit();
fe_ignore_messages_deinit();
fe_recode_deinit();
theme_unregister();
theme_unregister();
themes_deinit();
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
}
void glog_func(const char *log_domain, GLogLevelFlags log_level,

View file

@ -154,42 +154,66 @@ static void cmd_server_add_modify(const char *data, gboolean add)
else if (g_hash_table_lookup(optlist, "4"))
rec->family = AF_INET;
if (g_hash_table_lookup(optlist, "ssl"))
rec->use_ssl = TRUE;
if (g_hash_table_lookup(optlist, "tls") || g_hash_table_lookup(optlist, "ssl"))
rec->use_tls = TRUE;
value = g_hash_table_lookup(optlist, "ssl_cert");
value = g_hash_table_lookup(optlist, "tls_cert");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_cert");
if (value != NULL && *value != '\0')
rec->ssl_cert = g_strdup(value);
rec->tls_cert = g_strdup(value);
value = g_hash_table_lookup(optlist, "ssl_pkey");
value = g_hash_table_lookup(optlist, "tls_pkey");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_pkey");
if (value != NULL && *value != '\0')
rec->ssl_pkey = g_strdup(value);
rec->tls_pkey = g_strdup(value);
value = g_hash_table_lookup(optlist, "ssl_pass");
value = g_hash_table_lookup(optlist, "tls_pass");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_pass");
if (value != NULL && *value != '\0')
rec->ssl_pass = g_strdup(value);
rec->tls_pass = g_strdup(value);
if (g_hash_table_lookup(optlist, "ssl_verify"))
rec->ssl_verify = TRUE;
if (g_hash_table_lookup(optlist, "tls_verify") || g_hash_table_lookup(optlist, "ssl_verify"))
rec->tls_verify = TRUE;
value = g_hash_table_lookup(optlist, "ssl_cafile");
value = g_hash_table_lookup(optlist, "tls_cafile");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_cafile");
if (value != NULL && *value != '\0')
rec->ssl_cafile = g_strdup(value);
rec->tls_cafile = g_strdup(value);
value = g_hash_table_lookup(optlist, "ssl_capath");
value = g_hash_table_lookup(optlist, "tls_capath");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_capath");
if (value != NULL && *value != '\0')
rec->ssl_capath = g_strdup(value);
rec->tls_capath = g_strdup(value);
value = g_hash_table_lookup(optlist, "ssl_ciphers");
value = g_hash_table_lookup(optlist, "tls_ciphers");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_ciphers");
if (value != NULL && *value != '\0')
rec->ssl_ciphers = g_strdup(value);
rec->tls_ciphers = g_strdup(value);
if ((rec->ssl_cafile != NULL && rec->ssl_cafile[0] != '\0')
|| (rec->ssl_capath != NULL && rec->ssl_capath[0] != '\0'))
rec->ssl_verify = TRUE;
value = g_hash_table_lookup(optlist, "tls_pinned_cert");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_pinned_cert");
if (value != NULL && *value != '\0')
rec->tls_pinned_cert = g_strdup(value);
if ((rec->ssl_cert != NULL && rec->ssl_cert[0] != '\0') || rec->ssl_verify == TRUE)
rec->use_ssl = TRUE;
value = g_hash_table_lookup(optlist, "tls_pinned_pubkey");
if (value == NULL)
value = g_hash_table_lookup(optlist, "ssl_pinned_pubkey");
if (value != NULL && *value != '\0')
rec->tls_pinned_pubkey = g_strdup(value);
if ((rec->tls_cafile != NULL && rec->tls_cafile[0] != '\0')
|| (rec->tls_capath != NULL && rec->tls_capath[0] != '\0'))
rec->tls_verify = TRUE;
if ((rec->tls_cert != NULL && rec->tls_cert[0] != '\0') || rec->tls_verify == TRUE)
rec->use_tls = TRUE;
if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE;
if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE;
@ -331,8 +355,7 @@ static void sig_server_connected(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
TXT_CONNECTION_ESTABLISHED, server->connrec->address);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONNECTION_ESTABLISHED, server->connrec->address);
}
static void sig_connect_failed(SERVER_REC *server, gchar *msg)
@ -409,8 +432,9 @@ void fe_server_init(void)
command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove);
command_bind_first("server", NULL, (SIGNAL_FUNC) server_command);
command_bind_first("disconnect", NULL, (SIGNAL_FUNC) server_command);
command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd");
command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd");
command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey auto noauto proxy noproxy -host -port noautosendcmd");
command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey auto noauto proxy noproxy -host -port noautosendcmd");
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2015 Alexander Færøy <ahf@irssi.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
*/
#include "module.h"
#include "signals.h"
#include "settings.h"
#include "levels.h"
#include "tls.h"
#include "module-formats.h"
#include "printtext.h"
#include "fe-tls.h"
static void tls_handshake_finished(SERVER_REC *server, TLS_REC *tls)
{
if (! settings_get_bool("tls_verbose_connect"))
return;
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_HEADER);
GSList *certs = NULL;
for (certs = tls->certs; certs != NULL; certs = certs->next) {
TLS_CERT_REC *tls_cert_rec = certs->data;
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_SUBJECT_HEADER);
GSList *subject = NULL;
for (subject = tls_cert_rec->subject; subject != NULL; subject = subject->next) {
TLS_CERT_ENTRY_REC *subject_data = subject->data;
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_NAMED_ENTRY, subject_data->name, subject_data->value);
}
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_ISSUER_HEADER);
GSList *issuer = NULL;
for (issuer = tls_cert_rec->issuer; issuer != NULL; issuer = issuer->next) {
TLS_CERT_ENTRY_REC *issuer_data = issuer->data;
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_NAMED_ENTRY, issuer_data->name, issuer_data->value);
}
}
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PROTOCOL_VERSION, tls->protocol_version, tls->cipher_size, tls->cipher);
#ifdef SSL_get_server_tmp_key
if (tls->ephemeral_key_algorithm != NULL)
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_EPHEMERAL_KEY, tls->ephemeral_key_size, tls->ephemeral_key_algorithm);
else
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_EPHEMERAL_KEY_UNAVAILBLE);
#endif
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PUBLIC_KEY, tls->public_key_size, tls->public_key_algorithm, tls->not_before, tls->not_after);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PUBLIC_KEY_FINGERPRINT, tls->public_key_fingerprint, tls->public_key_fingerprint_algorithm);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERTIFICATE_FINGERPRINT, tls->certificate_fingerprint, tls->certificate_fingerprint_algorithm);
}
void fe_tls_init(void)
{
settings_add_bool("lookandfeel", "tls_verbose_connect", TRUE);
signal_add("tls handshake finished", (SIGNAL_FUNC)tls_handshake_finished);
}
void fe_tls_deinit(void)
{
signal_remove("tls handshake finished", (SIGNAL_FUNC)tls_handshake_finished);
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2015 Alexander Færøy <ahf@irssi.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
*/
#ifndef __FE_TLS_H
#define __FE_TLS_H
void fe_tls_init(void);
void fe_tls_deinit(void);
#endif

View file

@ -291,5 +291,19 @@ FORMAT_REC fecommon_core_formats[] = {
{ "completion_line", "%#$[10]0 $[!40]1 $2", 3, { 0, 0, 0 } },
{ "completion_footer", "", 0 },
/* ---- */
{ NULL, "TLS", 0 },
{ "tls_ephemeral_key", "EDH Key: {hilight $0} bit {hilight $1}", 2, { 1, 0 } },
{ "tls_ephemeral_key_unavailable", "EDH Key: {error N/A}", 0 },
{ "tls_public_key", "Public Key: {hilight $0} bit {hilight $1}, valid from {hilight $2} to {hilight $3}", 4, { 1, 0, 0, 0 } },
{ "tls_cert_header", "Certificate Chain:", 0 },
{ "tls_cert_subject_header", " Subject:", 0 },
{ "tls_cert_issuer_header", " Issuer:", 0 },
{ "tls_cert_named_entry", " $[-2]0: {hilight $1}", 2, { 0, 0 } },
{ "tls_public_key_fingerprint", "Public Key Fingerprint: {hilight $0} ({hilight $1})", 2, { 0, 0 } },
{ "tls_certificate_fingerprint", "Certificate Fingerprint: {hilight $0} ({hilight $1})", 2, { 0, 0 } },
{ "tls_protocol_version", "Protocol: {hilight $0} ({hilight $1} bit, {hilight $2})", 3, { 0, 1, 0 } },
{ NULL, NULL, 0 }
};

View file

@ -48,8 +48,8 @@ enum {
TXT_LOOKING_UP,
TXT_CONNECTING,
TXT_RECONNECTING,
TXT_CONNECTION_ESTABLISHED,
TXT_RECONNECTING,
TXT_CONNECTION_ESTABLISHED,
TXT_CANT_CONNECT,
TXT_CONNECTION_LOST,
TXT_LAG_DISCONNECTED,
@ -254,7 +254,20 @@ enum {
TXT_COMPLETION_REMOVED,
TXT_COMPLETION_HEADER,
TXT_COMPLETION_LINE,
TXT_COMPLETION_FOOTER
TXT_COMPLETION_FOOTER,
TLS_FILL_15,
TXT_TLS_EPHEMERAL_KEY,
TXT_TLS_EPHEMERAL_KEY_UNAVAILBLE,
TXT_TLS_PUBLIC_KEY,
TXT_TLS_CERT_HEADER,
TXT_TLS_CERT_SUBJECT_HEADER,
TXT_TLS_CERT_ISSUER_HEADER,
TXT_TLS_CERT_NAMED_ENTRY,
TXT_TLS_PUBLIC_KEY_FINGERPRINT,
TXT_TLS_CERTIFICATE_FINGERPRINT,
TXT_TLS_PROTOCOL_VERSION
};
extern FORMAT_REC fecommon_core_formats[];

View file

@ -108,23 +108,27 @@ static void cmd_server_list(const char *data)
g_string_append(str, "autoconnect, ");
if (rec->no_proxy)
g_string_append(str, "noproxy, ");
if (rec->use_ssl) {
g_string_append(str, "ssl, ");
if (rec->ssl_cert) {
g_string_append_printf(str, "ssl_cert: %s, ", rec->ssl_cert);
if (rec->ssl_pkey)
g_string_append_printf(str, "ssl_pkey: %s, ", rec->ssl_pkey);
if (rec->ssl_pass)
if (rec->use_tls) {
g_string_append(str, "tls, ");
if (rec->tls_cert) {
g_string_append_printf(str, "tls_cert: %s, ", rec->tls_cert);
if (rec->tls_pkey)
g_string_append_printf(str, "tls_pkey: %s, ", rec->tls_pkey);
if (rec->tls_pass)
g_string_append_printf(str, "(pass), ");
}
if (rec->ssl_verify)
g_string_append(str, "ssl_verify, ");
if (rec->ssl_cafile)
g_string_append_printf(str, "ssl_cafile: %s, ", rec->ssl_cafile);
if (rec->ssl_capath)
g_string_append_printf(str, "ssl_capath: %s, ", rec->ssl_capath);
if (rec->ssl_ciphers)
g_string_append_printf(str, "ssl_ciphers: %s, ", rec->ssl_ciphers);
if (rec->tls_verify)
g_string_append(str, "tls_verify, ");
if (rec->tls_cafile)
g_string_append_printf(str, "tls_cafile: %s, ", rec->tls_cafile);
if (rec->tls_capath)
g_string_append_printf(str, "tls_capath: %s, ", rec->tls_capath);
if (rec->tls_ciphers)
g_string_append_printf(str, "tls_ciphers: %s, ", rec->tls_ciphers);
if (rec->tls_pinned_cert)
g_string_append_printf(str, "tls_pinned_cert: %s, ", rec->tls_pinned_cert);
if (rec->tls_pinned_pubkey)
g_string_append_printf(str, "tls_pinned_pubkey: %s, ", rec->tls_pinned_pubkey);
}
if (rec->max_cmds_at_once > 0)

View file

@ -310,7 +310,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
if (server->connrec->port <= 0) {
server->connrec->port =
server->connrec->use_ssl ? 6697 : 6667;
server->connrec->use_tls ? 6697 : 6667;
}
server->cmd_queue_speed = ircconn->cmd_queue_speed > 0 ?
@ -328,7 +328,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
ircconn->max_whois : DEFAULT_MAX_WHOIS;
server->max_msgs_in_cmd = ircconn->max_msgs > 0 ?
ircconn->max_msgs : DEFAULT_MAX_MSGS;
server->connrec->use_ssl = conn->use_ssl;
server->connrec->use_tls = conn->use_tls;
modes_server_init(server);

View file

@ -37,6 +37,7 @@ while (<STDIN>) {
RAWLOG_REC => 'Irssi::Rawlog',
IGNORE_REC => 'Irssi::Ignore',
MODULE_REC => 'Irssi::Module',
TLS_REC => 'iobject',
# irc
BAN_REC => 'Irssi::Irc::Ban',

View file

@ -301,7 +301,8 @@ void perl_connect_fill_hash(HV *hv, SERVER_CONNECT_REC *conn)
(void) hv_store(hv, "no_autojoin_channels", 20, newSViv(conn->no_autojoin_channels), 0);
(void) hv_store(hv, "no_autosendcmd", 14, newSViv(conn->no_autosendcmd), 0);
(void) hv_store(hv, "unix_socket", 11, newSViv(conn->unix_socket), 0);
(void) hv_store(hv, "use_ssl", 7, newSViv(conn->use_ssl), 0);
(void) hv_store(hv, "use_ssl", 7, newSViv(conn->use_tls), 0);
(void) hv_store(hv, "use_tls", 7, newSViv(conn->use_tls), 0);
(void) hv_store(hv, "no_connect", 10, newSViv(conn->no_connect), 0);
}