---
 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


Reply via email to