From 43b0d36ee182f48cd655187a63411045aa04c948 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 16 Nov 2003 17:53:55 +0000 Subject: [PATCH] Support for sending SSL certificate to server and optionally verify server's certificate. See the -ssl_* options for /SERVER and /SERVER ADD. Patch by Joel Eriksson . git-svn-id: http://svn.irssi.org/repos/irssi/trunk@3146 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/core/chat-commands.c | 35 +++++-- src/core/network-openssl.c | 150 +++++++++++++++++++++++++++--- src/core/network.h | 2 +- src/core/server-connect-rec.h | 6 ++ src/core/server-setup-rec.h | 6 ++ src/core/servers-reconnect.c | 5 + src/core/servers-setup.c | 35 +++++++ src/core/servers.c | 8 +- src/core/session.c | 5 + src/fe-common/core/fe-server.c | 28 +++++- src/fe-common/irc/fe-irc-server.c | 25 ++++- 11 files changed, 275 insertions(+), 30 deletions(-) diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index 16c3a0e9..ad9313ed 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -40,7 +40,7 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, CHAT_PROTOCOL_REC *proto; SERVER_CONNECT_REC *conn; GHashTable *optlist; - char *addr, *portstr, *password, *nick, *chatnet, *host; + char *addr, *portstr, *password, *nick, *chatnet, *host, *tmp; void *free_arg; g_return_val_if_fail(data != NULL, NULL); @@ -88,7 +88,22 @@ 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) + 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 (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 ((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, "!") != NULL) @@ -112,9 +127,11 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, return conn; } -/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-noproxy] [-ircnet ] - [-host ] [-rawlog ] -
| [ [ []]] */ +/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ssl_cert ] [-ssl_pkey ] + [-ssl_verify] [-ssl_cafile ] [-ssl_capath ] + [-noproxy] [-ircnet ] [-host ] + [-rawlog ] +
| [ [ []]] */ static void cmd_connect(const char *data) { SERVER_CONNECT_REC *conn; @@ -214,8 +231,10 @@ static void sig_default_command_server(const char *data, SERVER_REC *server, signal_emit("command server connect", 3, data, server, item); } -/* SYNTAX: SERVER [-4 | -6] [-ssl] [-noproxy] [-ircnet ] - [-host ] [-rawlog ] +/* SYNTAX: SERVER [-4 | -6] [-ssl] [-ssl_cert ] [-ssl_pkey ] + [-ssl_verify] [-ssl_cafile ] [-ssl_capath ] + [-noproxy] [-ircnet ] [-host ] + [-rawlog ] [+]
| [ [ []]] */ static void cmd_server_connect(const char *data, SERVER_REC *server) { @@ -445,7 +464,7 @@ void chat_commands_init(void) signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server); - command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog"); + command_set_options("connect", "4 6 !! ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath +host noproxy -rawlog"); command_set_options("join", "invite"); command_set_options("msg", "channel nick"); } diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c index c88b5050..1ae3a589 100644 --- a/src/core/network-openssl.c +++ b/src/core/network-openssl.c @@ -20,6 +20,7 @@ #include "module.h" #include "network.h" +#include "misc.h" #ifdef HAVE_OPENSSL @@ -36,14 +37,20 @@ typedef struct gint fd; GIOChannel *giochan; SSL *ssl; - X509 *cert; + SSL_CTX *ctx; + unsigned int got_cert:1; + unsigned int verify:1; } GIOSSLChannel; +static SSL_CTX *ssl_ctx = NULL; + static void irssi_ssl_free(GIOChannel *handle) { GIOSSLChannel *chan = (GIOSSLChannel *)handle; g_io_channel_unref(chan->giochan); SSL_free(chan->ssl); + if (chan->ctx != ssl_ctx) + SSL_CTX_free(chan->ctx); g_free(chan); } @@ -70,17 +77,63 @@ GIOError ssl_errno(gint e) return G_IO_ERROR_INVAL; } +static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, X509 *cert) +{ + if (SSL_get_verify_result(ssl) != X509_V_OK) { + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n; + char *str; + + g_warning("Could not verify SSL servers certificate:"); + 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); + } + } + return FALSE; + } + return TRUE; +} + static GIOError irssi_ssl_cert_step(GIOSSLChannel *chan) { + X509 *cert; gint err; switch(err = SSL_do_handshake(chan->ssl)) { case 1: - if(!(chan->cert = SSL_get_peer_certificate(chan->ssl))) + if(!(cert = SSL_get_peer_certificate(chan->ssl))) { g_warning("SSL server supplied no certificate"); return G_IO_ERROR_INVAL; } + if (chan->verify && ! irssi_ssl_verify(chan->ssl, chan->ctx, cert)) { + X509_free(cert); + return G_IO_ERROR_INVAL; + } + X509_free(cert); return G_IO_ERROR_NONE; default: if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ) @@ -96,7 +149,7 @@ static GIOError irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint GIOSSLChannel *chan = (GIOSSLChannel *)handle; gint err; - if(chan->cert == NULL) + if(! chan->got_cert) { gint cert_err = irssi_ssl_cert_step(chan); if(cert_err != G_IO_ERROR_NONE) @@ -125,7 +178,7 @@ static GIOError irssi_ssl_write(GIOChannel *handle, gchar *buf, guint len, guint GIOSSLChannel *chan = (GIOSSLChannel *)handle; gint err; - if(chan->cert == NULL) + if(chan->got_cert) { gint cert_err = irssi_ssl_cert_step(chan); if(cert_err != G_IO_ERROR_NONE) @@ -208,15 +261,21 @@ GIOStatus ssl_errno(gint e) static GIOStatus irssi_ssl_cert_step(GIOSSLChannel *chan) { + X509 *cert; gint err; switch(err = SSL_do_handshake(chan->ssl)) { case 1: - if(!(chan->cert = SSL_get_peer_certificate(chan->ssl))) + 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) @@ -232,7 +291,7 @@ static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint GIOSSLChannel *chan = (GIOSSLChannel *)handle; gint err; - if(chan->cert == NULL) + if(! chan->got_cert) { gint cert_err = irssi_ssl_cert_step(chan); if(cert_err != G_IO_STATUS_NORMAL) @@ -261,7 +320,7 @@ static GIOStatus irssi_ssl_write(GIOChannel *handle, const gchar *buf, gsize len GIOSSLChannel *chan = (GIOSSLChannel *)handle; gint err; - if(chan->cert == NULL) + if(! chan->got_cert) { gint cert_err = irssi_ssl_cert_step(chan); if(cert_err != G_IO_STATUS_NORMAL) @@ -335,8 +394,6 @@ static GIOFuncs irssi_ssl_channel_funcs = { #endif -static SSL_CTX *ssl_ctx = NULL; - static gboolean irssi_ssl_init(void) { SSL_library_init(); @@ -353,13 +410,14 @@ static gboolean irssi_ssl_init(void) } -static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle) +static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify) { GIOSSLChannel *chan; GIOChannel *gchan; int err, fd; SSL *ssl; X509 *cert = NULL; + SSL_CTX *ctx = NULL; g_return_val_if_fail(handle != NULL, NULL); @@ -369,7 +427,52 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle) if(!(fd = g_io_channel_unix_get_fd(handle))) return NULL; - if(!(ssl = SSL_new(ssl_ctx))) + if (mycert && *mycert) { + char *scert = NULL, *spkey = NULL; + if ((ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { + g_error("Could not allocate memory for SSL context"); + return NULL; + } + scert = convert_home(mycert); + if (mypkey && *mypkey) + spkey = convert_home(mypkey); + if (! SSL_CTX_use_certificate_file(ctx, scert, SSL_FILETYPE_PEM)) + g_warning("Loading of client certificate '%s' failed", mycert); + else if (! SSL_CTX_use_PrivateKey_file(ctx, spkey ? spkey : scert, SSL_FILETYPE_PEM)) + g_warning("Loading of private key '%s' failed", mypkey ? mypkey : mycert); + else if (! SSL_CTX_check_private_key(ctx)) + g_warning("Private key does not match the certificate"); + g_free(scert); + g_free(spkey); + } + + if ((cafile && *cafile) || (capath && *capath)) { + char *scafile = NULL; + char *scapath = NULL; + if (! ctx && (ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { + g_error("Could not allocate memory for SSL context"); + return NULL; + } + if (cafile && *cafile) + scafile = convert_home(cafile); + if (capath && *capath) + scapath = convert_home(capath); + if (! SSL_CTX_load_verify_locations(ctx, scafile, scapath)) { + g_warning("Could not load CA list for verifying SSL server certificate"); + g_free(scafile); + g_free(scapath); + SSL_CTX_free(ctx); + return NULL; + } + g_free(scafile); + g_free(scapath); + verify = TRUE; + } + + if (ctx == NULL) + ctx = ssl_ctx; + + if(!(ssl = SSL_new(ctx))) { g_warning("Failed to allocate SSL structure"); return NULL; @@ -378,6 +481,9 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle) if(!(err = SSL_set_fd(ssl, fd))) { g_warning("Failed to associate socket to SSL stream"); + SSL_free(ssl); + if (ctx != ssl_ctx) + SSL_CTX_free(ctx); return NULL; } @@ -391,22 +497,38 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle) 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->fd = fd; chan->giochan = handle; chan->ssl = ssl; - chan->cert = cert; + chan->ctx = ctx; + chan->got_cert = cert != NULL; + chan->verify = verify; g_io_channel_ref(handle); gchan = (GIOChannel *)chan; @@ -416,10 +538,10 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle) return gchan; } -GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip) +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 *gret = net_connect_ip(ip, port, my_ip); - gret = irssi_ssl_get_iochannel(gret); + gret = irssi_ssl_get_iochannel(gret, cert, pkey, cafile, capath, verify); return gret; } diff --git a/src/core/network.h b/src/core/network.h index 68f869ea..5e445e83 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -47,7 +47,7 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2); /* Connect to socket */ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip); /* Connect to socket with ip address and SSL*/ -GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip); +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); /* Connect to socket with ip address */ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip); /* Connect to named UNIX socket */ diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h index 8ef2d0ad..a52e5b0a 100644 --- a/src/core/server-connect-rec.h +++ b/src/core/server-connect-rec.h @@ -23,6 +23,11 @@ char *nick; char *username; char *realname; +char *ssl_cert; +char *ssl_pkey; +char *ssl_cafile; +char *ssl_capath; + GIOChannel *connect_handle; /* connect using this handle */ /* when reconnecting, the old server status */ @@ -30,6 +35,7 @@ unsigned int reconnection:1; /* we're trying to reconnect */ unsigned int no_autojoin_channels:1; /* don't autojoin any channels */ 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 no_connect:1; /* don't connect() at all, it's done by plugin */ char *channels; char *away_reason; diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index d04fa1fe..b7a0c80d 100644 --- a/src/core/server-setup-rec.h +++ b/src/core/server-setup-rec.h @@ -8,6 +8,11 @@ char *address; int port; char *password; +char *ssl_cert; +char *ssl_pkey; +char *ssl_cafile; +char *ssl_capath; + char *own_host; /* address to use when connecting this server */ IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */ @@ -19,5 +24,6 @@ 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; GHashTable *module_data; diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c index beeddc94..1e5a3763 100644 --- a/src/core/servers-reconnect.c +++ b/src/core/servers-reconnect.c @@ -191,6 +191,11 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info) dest->no_autojoin_channels = src->no_autojoin_channels; 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); return dest; } diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index 6bdafb80..2aeb1d5d 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -163,7 +163,17 @@ static void server_setup_fill_server(SERVER_CONNECT_REC *conn, conn->family = sserver->family; 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); + 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); server_setup_fill_reconn(conn, sserver); @@ -394,6 +404,15 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) 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_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)); + if (rec->ssl_cafile || rec->ssl_capath) + rec->ssl_verify = TRUE; + if (rec->ssl_cert != NULL || rec->ssl_verify) + rec->use_ssl = TRUE; rec->port = port; rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE); rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE); @@ -424,6 +443,11 @@ 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_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, "own_host", rec->own_host); iconfig_node_set_str(node, "family", @@ -460,6 +484,10 @@ 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_cafile); + g_free_not_null(rec->ssl_capath); g_free(rec->address); g_free(rec); } @@ -517,6 +545,13 @@ void servers_setup_init(void) settings_add_str("server", "user_name", NULL); settings_add_str("server", "real_name", NULL); + settings_add_bool("server", "use_ssl", FALSE); + settings_add_str("server", "ssl_cert", NULL); + settings_add_str("server", "ssl_pkey", NULL); + settings_add_bool("server", "ssl_verify", FALSE); + settings_add_str("server", "ssl_cafile", NULL); + settings_add_str("server", "ssl_cacert", NULL); + settings_add_bool("proxy", "use_proxy", FALSE); settings_add_str("proxy", "proxy_address", ""); settings_add_int("proxy", "proxy_port", 6667); diff --git a/src/core/servers.c b/src/core/servers.c index 887efd4b..85bc203b 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -188,7 +188,8 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip, port = server->connrec->proxy != NULL ? server->connrec->proxy_port : server->connrec->port; handle = server->connrec->use_ssl ? - net_connect_ip_ssl(ip, port, own_ip) : + net_connect_ip_ssl(ip, port, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey, +server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_verify) : net_connect_ip(ip, port, own_ip); } else { handle = net_connect_unix(unix_socket); @@ -584,6 +585,11 @@ void server_connect_unref(SERVER_CONNECT_REC *conn) 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_cafile); + g_free_not_null(conn->ssl_capath); + g_free_not_null(conn->channels); g_free_not_null(conn->away_reason); diff --git a/src/core/session.c b/src/core/session.c index f912b831..ec589d70 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -183,6 +183,11 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config, config_node_set_str(config, node, "nick", server->nick); 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); handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle)); config_node_set_int(config, node, "handle", handle); diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index fdc676af..84052afb 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -147,6 +147,32 @@ static void cmd_server_add(const char *data) if (g_hash_table_lookup(optlist, "ssl")) rec->use_ssl = TRUE; + value = g_hash_table_lookup(optlist, "ssl_cert"); + if (value != NULL && *value != '\0') + rec->ssl_cert = g_strdup(value); + + value = g_hash_table_lookup(optlist, "ssl_pkey"); + if (value != NULL && *value != '\0') + rec->ssl_pkey = g_strdup(value); + + if (g_hash_table_lookup(optlist, "ssl_verify")) + rec->ssl_verify = TRUE; + + value = g_hash_table_lookup(optlist, "ssl_cafile"); + if (value != NULL && *value != '\0') + rec->ssl_cafile = g_strdup(value); + + value = g_hash_table_lookup(optlist, "ssl_capath"); + if (value != NULL && *value != '\0') + rec->ssl_capath = 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; + + if ((rec->ssl_cert != NULL && rec->ssl_cert[0] != '\0') || rec->ssl_verify == TRUE) + rec->use_ssl = TRUE; + if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE; if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE; if (g_hash_table_lookup(optlist, "proxy")) rec->no_proxy = FALSE; @@ -343,7 +369,7 @@ 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 auto noauto proxy noproxy -host -port"); + command_set_options("server add", "4 6 ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath auto noauto proxy noproxy -host -port"); signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting); diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c index 44563000..a07ff6d0 100644 --- a/src/fe-common/irc/fe-irc-server.c +++ b/src/fe-common/irc/fe-irc-server.c @@ -50,9 +50,11 @@ const char *get_visible_target(IRC_SERVER_REC *server, const char *target) return target; } -/* SYNTAX: SERVER ADD [-4 | -6] [-ssl] [-auto | -noauto] [-ircnet ] - [-host ] [-cmdspeed ] [-cmdmax ] - [-port ]
[ []] */ +/* SYNTAX: SERVER ADD [-4 | -6] [-ssl] [-ssl_cert ] [-ssl_pkey ] + [-ssl_verify] [-ssl_cafile ] [-ssl_capath ] + [-auto | -noauto] [-ircnet ] [-host ] + [-cmdspeed ] [-cmdmax ] [-port ] +
[ []] */ static void sig_server_add_fill(IRC_SERVER_SETUP_REC *rec, GHashTable *optlist) { @@ -98,8 +100,21 @@ 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->use_ssl) { + g_string_append(str, "ssl, "); + if (rec->ssl_cert) { + g_string_sprintfa(str, "ssl_cert: %s, ", rec->ssl_cert); + if (rec->ssl_pkey) + g_string_sprintfa(str, "ssl_pkey: %s, ", rec->ssl_pkey); + } + if (rec->ssl_verify) + g_string_append(str, "ssl_verify, "); + if (rec->ssl_cafile) + g_string_sprintfa(str, "ssl_cafile: %s, ", rec->ssl_cafile); + if (rec->ssl_capath) + g_string_sprintfa(str, "ssl_capath: %s, ", rec->ssl_capath); + + } if (rec->max_cmds_at_once > 0) g_string_sprintfa(str, "cmdmax: %d, ", rec->max_cmds_at_once); if (rec->cmd_queue_speed > 0)