---
src/core/network-openssl.c | 26 +++++++++++++++++++++++++-
src/core/server-connect-rec.h | 1 +
src/core/server-setup-rec.h | 1 +
src/core/servers-reconnect.c | 1 +
src/core/servers-setup.c | 7 ++++++-
src/core/servers.c | 1 +
src/core/session.c | 1 +
7 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c
index efb7525..6daa612 100644
--- a/src/core/network-openssl.c
+++ b/src/core/network-openssl.c
@@ -282,6 +282,29 @@ static gboolean irssi_ssl_verify(SSL *ssl, const char
*hostname, int port, X509
return TRUE;
}
+static gboolean match_fingerprint(X509 *cert, const char *fingerprint)
+{
+ unsigned char md[EVP_MAX_MD_SIZE];
+ unsigned int i, n;
+ char fp[EVP_MAX_MD_SIZE*3];
+
+ if (! X509_digest(cert, EVP_sha256(), md, &n)) {
+ g_warning("Could not get fingerprint from peer certificate");
+ return FALSE;
+ }
+
+ for (i = 0; i < n; i++)
+ sprintf(fp + 3 * i, "%02X%c", md[i], i + 1 == n ? '\0' : ':');
+
+ if (strcmp(fp, fingerprint) != 0) {
+ g_warning("Fingerprint mismatch");
+ g_warning("Got %s", fp);
+ g_warning("Need %s", fingerprint);
+ return FALSE;
+ }
+ return TRUE;
+}
+
static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, gsize len,
gsize *ret, GError **gerr)
{
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
@@ -601,7 +624,8 @@ int irssi_ssl_handshake(GIOChannel *handle)
g_warning("SSL server supplied no certificate");
return -1;
}
- ret = !chan->verify || irssi_ssl_verify(chan->ssl,
chan->server->connrec->address, chan->port, cert, chan->server);
+ ret = (!chan->verify || irssi_ssl_verify(chan->ssl,
chan->server->connrec->address, chan->port, cert, chan->server)) &&
+ (chan->server->connrec->ssl_sha256 == NULL ||
match_fingerprint(cert, chan->server->connrec->ssl_sha256));
X509_free(cert);
return ret ? 0 : -1;
}
diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h
index 1753750..04ad047 100644
--- a/src/core/server-connect-rec.h
+++ b/src/core/server-connect-rec.h
@@ -28,6 +28,7 @@ char *ssl_pkey;
char *ssl_pass;
char *ssl_cafile;
char *ssl_capath;
+char *ssl_sha256;
GIOChannel *connect_handle; /* connect using this handle */
diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h
index ae79755..53e5978 100644
--- a/src/core/server-setup-rec.h
+++ b/src/core/server-setup-rec.h
@@ -13,6 +13,7 @@ char *ssl_pkey;
char *ssl_pass;
char *ssl_cafile;
char *ssl_capath;
+char *ssl_sha256;
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 0a08b46..069bbf4 100644
--- a/src/core/servers-reconnect.c
+++ b/src/core/servers-reconnect.c
@@ -197,6 +197,7 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int
connect_info)
dest->ssl_verify = src->ssl_verify;
dest->ssl_cafile = g_strdup(src->ssl_cafile);
dest->ssl_capath = g_strdup(src->ssl_capath);
+ dest->ssl_sha256 = g_strdup(src->ssl_sha256);
return dest;
}
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c
index 0819ff1..42c6b3a 100644
--- a/src/core/servers-setup.c
+++ b/src/core/servers-setup.c
@@ -176,6 +176,8 @@ static void server_setup_fill_server(SERVER_CONNECT_REC
*conn,
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_sha256 == NULL && sserver->ssl_sha256 != NULL &&
sserver->ssl_sha256[0] != '\0')
+ conn->ssl_sha256 = g_strdup(sserver->ssl_sha256);
server_setup_fill_reconn(conn, sserver);
@@ -402,9 +404,10 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE
*node)
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_sha256 = g_strdup(config_node_get_str(node, "ssl_sha256",
NULL));
if (rec->ssl_cafile || rec->ssl_capath)
rec->ssl_verify = TRUE;
- if (rec->ssl_cert != NULL || rec->ssl_verify)
+ if (rec->ssl_cert != NULL || rec->ssl_verify || rec->ssl_sha256 != NULL)
rec->use_ssl = TRUE;
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
@@ -442,6 +445,7 @@ static void server_setup_save(SERVER_SETUP_REC *rec)
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_sha256", rec->ssl_sha256);
iconfig_node_set_str(node, "own_host", rec->own_host);
iconfig_node_set_str(node, "family",
@@ -483,6 +487,7 @@ static void server_setup_destroy(SERVER_SETUP_REC *rec)
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_sha256);
g_free(rec->address);
g_free(rec);
}
diff --git a/src/core/servers.c b/src/core/servers.c
index 6eaad19..5457242 100644
--- a/src/core/servers.c
+++ b/src/core/servers.c
@@ -636,6 +636,7 @@ void server_connect_unref(SERVER_CONNECT_REC *conn)
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_sha256);
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 b300263..4159bad 100644
--- a/src/core/session.c
+++ b/src/core/session.c
@@ -165,6 +165,7 @@ static void session_save_server(SERVER_REC *server,
CONFIG_REC *config,
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_sha256",
server->connrec->ssl_sha256);
handle =
g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
config_node_set_int(config, node, "handle", handle);
--
1.8.4