summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS21
-rw-r--r--docs/help/in/connect.in2
-rw-r--r--docs/help/in/server.in2
-rw-r--r--src/core/chat-commands.c6
-rw-r--r--src/core/network-openssl.c20
-rw-r--r--src/core/server-connect-rec.h2
-rw-r--r--src/core/server-setup-rec.h2
-rw-r--r--src/core/servers-reconnect.c2
-rw-r--r--src/core/servers-setup.c18
-rw-r--r--src/core/servers.c2
-rw-r--r--src/core/session.c2
-rw-r--r--src/fe-common/core/fe-server.c15
-rw-r--r--src/fe-common/irc/fe-irc-server.c4
13 files changed, 95 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 4dad1712..e4431839 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,27 @@ v0.8.21-head 2016-xx-xx The Irssi team <staff@irssi.org>
configuration.
+ Display TLS connection information upon connect. You can disable this by
setting tls_verbose_connect to FALSE.
+ + Add -tls_pinned_cert and -tls_pinned_pubkey for x509 and public key pinning.
+
+ The values needed for -tls_pinned_cert and -tls_pinned_pubkey is shown
+ when connecting to a TLS enabled IRC server, but you can also find the
+ values like this: Start by downloading the certificate from a given IRC
+ server:
+
+ $ openssl s_client -connect chat.freenode.net:6697 < /dev/null 2>/dev/null | \
+ openssl x509 > freenode.cert
+
+ Find the value for -tls_pinned_cert:
+
+ $ openssl x509 -in freenode.cert -fingerprint -sha256 -noout
+
+ Find the value for -tls_pinned_pubkey:
+
+ $ openssl x509 -in freenode.cert -pubkey -noout | \
+ openssl pkey -pubin -outform der | \
+ openssl dgst -sha256 -c | \
+ tr a-z A-Z
+
- IP addresses are no longer stored when resolve_reverse_lookup is
used.
- /names and $[...] now uses utf8 string operations (#40, #411).
diff --git a/docs/help/in/connect.in b/docs/help/in/connect.in
index a0d793d2..e861ad74 100644
--- a/docs/help/in/connect.in
+++ b/docs/help/in/connect.in
@@ -15,6 +15,8 @@
-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.
diff --git a/docs/help/in/server.in b/docs/help/in/server.in
index ee1a30e1..60870111 100644
--- a/docs/help/in/server.in
+++ b/docs/help/in/server.in
@@ -24,6 +24,8 @@
-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.
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c
index db60e46f..c737b810 100644
--- a/src/core/chat-commands.c
+++ b/src/core/chat-commands.c
@@ -115,6 +115,10 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
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;
@@ -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 tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_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");
}
diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c
index c221624f..13db6e25 100644
--- a/src/core/network-openssl.c
+++ b/src/core/network-openssl.c
@@ -753,6 +753,8 @@ int irssi_ssl_handshake(GIOChannel *handle)
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();
@@ -814,6 +816,24 @@ int irssi_ssl_handshake(GIOChannel *handle)
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);
diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h
index 35577fd4..fa348769 100644
--- a/src/core/server-connect-rec.h
+++ b/src/core/server-connect-rec.h
@@ -29,6 +29,8 @@ 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 */
diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h
index 22876d4e..e6b0431c 100644
--- a/src/core/server-setup-rec.h
+++ b/src/core/server-setup-rec.h
@@ -17,6 +17,8 @@ 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 */
diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c
index 16ec1fac..1727704c 100644
--- a/src/core/servers-reconnect.c
+++ b/src/core/servers-reconnect.c
@@ -199,6 +199,8 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
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;
}
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c
index 01a36e1c..9492c58c 100644
--- a/src/core/servers-setup.c
+++ b/src/core/servers-setup.c
@@ -181,6 +181,10 @@ static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
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);
@@ -435,6 +439,16 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
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)
@@ -500,6 +514,8 @@ static void server_setup_save(SERVER_SETUP_REC *rec)
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);
@@ -550,6 +566,8 @@ static void server_setup_destroy(SERVER_SETUP_REC *rec)
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);
}
diff --git a/src/core/servers.c b/src/core/servers.c
index 2a14d510..b9faab81 100644
--- a/src/core/servers.c
+++ b/src/core/servers.c
@@ -633,6 +633,8 @@ void server_connect_unref(SERVER_CONNECT_REC *conn)
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);
diff --git a/src/core/session.c b/src/core/session.c
index 5b3303bb..34190c52 100644
--- a/src/core/session.c
+++ b/src/core/session.c
@@ -165,6 +165,8 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config,
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);
diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c
index b9522bc1..f4c1d3ee 100644
--- a/src/fe-common/core/fe-server.c
+++ b/src/fe-common/core/fe-server.c
@@ -196,6 +196,17 @@ static void cmd_server_add_modify(const char *data, gboolean add)
if (value != NULL && *value != '\0')
rec->tls_ciphers = g_strdup(value);
+ 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);
+
+ 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'))
@@ -423,8 +434,8 @@ void fe_server_init(void)
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 +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_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 +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_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);
diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c
index 36ed2bdc..c4435d8f 100644
--- a/src/fe-common/irc/fe-irc-server.c
+++ b/src/fe-common/irc/fe-irc-server.c
@@ -125,6 +125,10 @@ static void cmd_server_list(const char *data)
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)