]> jfr.im git - irc/hexchat/hexchat.git/commitdiff
Remove DH-AES/DH-BLOWFISH mechanisms and misc cleanup
authorPatrick Griffis <redacted>
Fri, 29 Jan 2016 22:41:08 +0000 (17:41 -0500)
committerPatrick Griffis <redacted>
Fri, 29 Jan 2016 22:41:08 +0000 (17:41 -0500)
- AES and Blowfish mechanisms are deemed insecure and servers
  have removed support for them
- Remove attempts to retry since we only support one mech
- Handle SASL 3.2's new syntax for supported mechs

src/common/hexchat.h
src/common/inbound.c
src/common/inbound.h
src/common/proto-irc.c
src/common/server.c
src/common/util.c
src/common/util.h

index a29ea1d8018820369489d6bc64b2cca2c5fb7429..51c9b9aa629b10410b8bea3ed3ca3857bc313dfd 100644 (file)
@@ -422,9 +422,7 @@ typedef struct session
 
 /* SASL Mechanisms */
 #define MECH_PLAIN 0
-#define MECH_BLOWFISH 1
-#define MECH_AES 2
-#define MECH_EXTERNAL 3
+#define MECH_EXTERNAL 1
 
 typedef struct server
 {
@@ -546,7 +544,6 @@ typedef struct server
        unsigned int skip_next_whois:1; /* hide whois output */
        unsigned int inside_whois:1;
        unsigned int doing_dns:1;                       /* /dns has been done */
-       unsigned int retry_sasl:1;              /* retrying another sasl mech */
        unsigned int end_of_motd:1;             /* end of motd reached (logged in) */
        unsigned int sent_quit:1;                       /* sent a QUIT already? */
        unsigned int use_listargs:1;            /* undernet and dalnet need /list >0,<10000 */
@@ -570,7 +567,6 @@ typedef struct server
        unsigned int have_cert:1;       /* have loaded a cert */
        unsigned int use_who:1;                 /* whether to use WHO command to get dcc_ip */
        unsigned int sasl_mech;                 /* mechanism for sasl auth */
-       unsigned int sent_saslauth:1;   /* have sent AUTHENICATE yet */
        unsigned int sent_capend:1;     /* have sent CAP END yet */
        unsigned int waiting_on_cap:1;  /* waiting on another line of CAP LS */
 #ifdef USE_OPENSSL
index 5f949822e934eacacb32716528aa9bb0120522d7..0e962cafa9b8d269f5440aab4c1dc3f1e0a627b0 100644 (file)
@@ -1633,6 +1633,12 @@ inbound_identified (server *serv)        /* 'MODE +e MYSELF' on freenode */
        }
 }
 
+static const char *sasl_mechanisms[] =
+{
+       "PLAIN",
+       "EXTERNAL"
+};
+
 static void
 inbound_toggle_caps (server *serv, const char *extensions_str, gboolean enable)
 {
@@ -1666,24 +1672,12 @@ inbound_toggle_caps (server *serv, const char *extensions_str, gboolean enable)
                        serv->have_sasl = enable;
                        if (enable)
                        {
-                               serv->sent_saslauth = FALSE;
-
 #ifdef USE_OPENSSL
                                if (serv->loginmethod == LOGIN_SASLEXTERNAL)
-                               {
                                        serv->sasl_mech = MECH_EXTERNAL;
-                                       tcp_send_len (serv, "AUTHENTICATE EXTERNAL\r\n", 23);
-                               }
-                               else
-                               {
-                                       /* default to most secure, it will fallback if not supported */
-                                       serv->sasl_mech = MECH_AES;
-                                       tcp_send_len (serv, "AUTHENTICATE DH-AES\r\n", 21);
-                               }
-#else
-                               serv->sasl_mech = MECH_PLAIN;
-                               tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);
 #endif
+                               /* Mechanism either defaulted to PLAIN or server gave us list */
+                               tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[serv->sasl_mech]);
                        }
                }
        }
@@ -1735,6 +1729,37 @@ static const char * const supported_caps[] = {
        "twitch.tv/membership",
 };
 
+static int
+get_supported_mech (server *serv, const char *list)
+{
+       char **mechs = g_strsplit (list, ",", 0);
+       gsize i;
+       int ret = -1;
+
+       for (i = 0; mechs[i]; ++i)
+       {
+#ifdef USE_OPENSSL
+               if (serv->loginmethod == LOGIN_SASLEXTERNAL)
+               {
+                       if (!strcmp (mechs[i], "EXTERNAL"))
+                       {
+                               ret = MECH_EXTERNAL;
+                               break;
+                       }
+               }
+               else
+#endif
+               if (!strcmp (mechs[i], "PLAIN"))
+               {
+                       ret = MECH_PLAIN;
+                       break;
+               }
+       }
+
+       g_strfreev (mechs);
+       return ret;
+}
+
 void
 inbound_cap_ls (server *serv, char *nick, char *extensions_str,
                                         const message_tags_data *tags_data)
@@ -1781,6 +1806,13 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
                        ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
                                || (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert)))
                {
+                       if (value)
+                       {
+                               int sasl_mech = get_supported_mech (serv, value);
+                               if (sasl_mech == -1) /* No supported mech */
+                                       continue;
+                               serv->sasl_mech = sasl_mech;
+                       }
                        want_cap = TRUE;
                        want_sasl = TRUE;
                        g_strlcat (buffer, "sasl ", sizeof(buffer));
@@ -1839,40 +1871,6 @@ inbound_cap_list (server *serv, char *nick, char *extensions,
                                                                  NULL, NULL, 0, tags_data->timestamp);
 }
 
-static const char *sasl_mechanisms[] =
-{
-       "PLAIN",
-       "DH-BLOWFISH",
-       "DH-AES",
-       "EXTERNAL"
-};
-
-void
-inbound_sasl_supportedmechs (server *serv, char *list)
-{
-       int i;
-
-       if (serv->sasl_mech != MECH_EXTERNAL)
-       {
-               /* Use most secure one supported */
-               for (i = MECH_AES; i >= MECH_PLAIN; i--)
-               {
-                       if (strstr (list, sasl_mechanisms[i]) != NULL)
-                       {
-                               serv->sasl_mech = i;
-                               serv->retry_sasl = TRUE;
-                               tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[i]);
-                               return;
-                       }
-               }
-       }
-
-       /* Abort, none supported */
-       serv->sent_saslauth = TRUE;
-       tcp_sendf (serv, "AUTHENTICATE *\r\n");
-       return;
-}
-
 void
 inbound_sasl_authenticate (server *serv, char *data)
 {
@@ -1880,12 +1878,10 @@ inbound_sasl_authenticate (server *serv, char *data)
                char *user, *pass = NULL;
                const char *mech = sasl_mechanisms[serv->sasl_mech];
 
-               /* Got a list of supported mechanisms from inspircd */
+               /* Got a list of supported mechanisms from outdated inspircd
+                * just ignore it as it goes against spec */
                if (strchr (data, ',') != NULL)
-               {
-                       inbound_sasl_supportedmechs (serv, data);
                        return;
-               }
 
                if (net->user && !(net->flags & FLAG_USE_GLOBAL))
                        user = net->user;
@@ -1898,12 +1894,6 @@ inbound_sasl_authenticate (server *serv, char *data)
                        pass = encode_sasl_pass_plain (user, serv->password);
                        break;
 #ifdef USE_OPENSSL
-               case MECH_BLOWFISH:
-                       pass = encode_sasl_pass_blowfish (user, serv->password, data);
-                       break;
-               case MECH_AES:
-                       pass = encode_sasl_pass_aes (user, serv->password, data);
-                       break;
                case MECH_EXTERNAL:
                        pass = g_strdup ("+");
                        break;
@@ -1913,12 +1903,10 @@ inbound_sasl_authenticate (server *serv, char *data)
                if (pass == NULL)
                {
                        /* something went wrong abort */
-                       serv->sent_saslauth = TRUE; /* prevent trying PLAIN */
                        tcp_sendf (serv, "AUTHENTICATE *\r\n");
                        return;
                }
 
-               serv->sent_saslauth = TRUE;
                tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass);
                g_free (pass);
 
@@ -1927,19 +1915,9 @@ inbound_sasl_authenticate (server *serv, char *data)
                                                                NULL,   NULL,   0,      0);
 }
 
-int
+void
 inbound_sasl_error (server *serv)
 {
-       if (serv->retry_sasl && !serv->sent_saslauth)
-               return 1;
-
-       /* If server sent 904 before we sent password,
-               * mech not support so fallback to next mech */
-       if (!serv->sent_saslauth && serv->sasl_mech != MECH_EXTERNAL && serv->sasl_mech != MECH_PLAIN)
-       {
-               serv->sasl_mech -= 1;
-               tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[serv->sasl_mech]);
-               return 1;
-       }
-       return 0;
+       /* Just abort, not much we can do */
+       tcp_sendf (serv, "AUTHENTICATE *\r\n");
 }
index c5d10445820c219bc35dbe22f6757d19c070eab6..83e78d5d8924815a24364ebb3e88309118ed1f35 100644 (file)
@@ -98,8 +98,7 @@ void inbound_cap_list (server *serv, char *nick, char *extensions,
 void inbound_cap_del (server *serv, char *nick, char *extensions,
                                                          const message_tags_data *tags_data);
 void inbound_sasl_authenticate (server *serv, char *data);
-int inbound_sasl_error (server *serv);
-void inbound_sasl_supportedmechs (server *serv, char *list);
+void inbound_sasl_error (server *serv);
 void do_dns (session *sess, char *nick, char *host,
                                 const message_tags_data *tags_data);
 gboolean alert_match_word (char *word, char *masks);
index 180a3e437c043ea6ff07366c27b79659684a1c37..a565dbb60e58d16939db5586a858b48263975c2b 100644 (file)
@@ -946,10 +946,9 @@ process_numeric (session * sess, int n,
                                                                          word_eol[6]+1, word[1], word[2], NULL, 0,
                                                                          tags_data->timestamp);
                break;
-       case 903:       /* successful SASL auth */
        case 904:       /* failed SASL auth */
-               if (inbound_sasl_error (serv))
-                       break; /* might retry */
+               inbound_sasl_error (serv);
+       case 903:       /* successful SASL auth */
        case 905:       /* failed SASL auth */
        case 906:       /* aborted */
        case 907:       /* attempting to re-auth after a successful auth */
@@ -963,7 +962,7 @@ process_numeric (session * sess, int n,
                }
                break;
        case 908:       /* Supported SASL Mechs */
-               inbound_sasl_supportedmechs (serv, word[4]);
+               /* ignored for now, SASL 3.2 is a better solution and we only do PLAIN atm */
                break;
 
        default:
index 926a9f43e164676271144259cca366821db3016e..e4c2e377187b1ae683413e7be3266d3250f1178c 100644 (file)
@@ -1727,6 +1727,7 @@ server_set_defaults (server *serv)
        serv->chanmodes = g_strdup ("beI,k,l");
        serv->nick_prefixes = g_strdup ("@%+");
        serv->nick_modes = g_strdup ("ohv");
+       serv->sasl_mech = MECH_PLAIN;
 
        server_set_encoding (serv, "UTF-8");
 
index 9ec8ef16df82c8d7bf07ba3afbd744ce5189ed13..5c4eb8bff0dc98bae8558d03a530d7745b7ebf95 100644 (file)
@@ -56,8 +56,6 @@
 #ifdef USE_OPENSSL
 #include <openssl/bn.h>
 #include <openssl/rand.h>
-#include <openssl/blowfish.h>
-#include <openssl/aes.h>
 #ifndef WIN32
 #include <netinet/in.h>
 #endif
@@ -1393,227 +1391,6 @@ encode_sasl_pass_plain (char *user, char *pass)
        return encoded;
 }
 
-#ifdef USE_OPENSSL
-/* Adapted from ZNC's SASL module */
-
-static int
-parse_dh (char *str, DH **dh_out, unsigned char **secret_out, int *keysize_out)
-{
-       DH *dh;
-       guchar *data, *decoded_data;
-       guchar *secret = NULL;
-       gsize data_len;
-       guint size;
-       guint16 size16;
-       BIGNUM *pubkey;
-       gint key_size;
-
-       dh = DH_new();
-       data = decoded_data = g_base64_decode (str, &data_len);
-       if (data_len < 2)
-               goto fail;
-
-       /* prime number */
-       memcpy (&size16, data, sizeof(size16));
-       size = ntohs (size16);
-       data += 2;
-       data_len -= 2;
-
-       if (size > data_len)
-               goto fail;
-
-       dh->p = BN_bin2bn (data, size, NULL);
-       data += size;
-
-       /* Generator */
-       if (data_len < 2)
-               goto fail;
-
-       memcpy (&size16, data, sizeof(size16));
-       size = ntohs (size16);
-       data += 2;
-       data_len -= 2;
-       
-       if (size > data_len)
-               goto fail;
-
-       dh->g = BN_bin2bn (data, size, NULL);
-       data += size;
-
-       /* pub key */
-       if (data_len < 2)
-               goto fail;
-
-       memcpy (&size16, data, sizeof(size16));
-       size = ntohs(size16);
-       data += 2;
-       data_len -= 2;
-
-       pubkey = BN_bin2bn (data, size, NULL);
-       if (!(DH_generate_key (dh)))
-               goto fail;
-
-       secret = g_malloc (DH_size (dh));
-       key_size = DH_compute_key (secret, pubkey, dh);
-       if (key_size == -1)
-               goto fail;
-
-       g_free (decoded_data);
-
-       *dh_out = dh;
-       *secret_out = secret;
-       *keysize_out = key_size;
-       return 1;
-
-fail:
-       g_free (secret);
-       g_free (decoded_data);
-
-       return 0;
-}
-
-char *
-encode_sasl_pass_blowfish (char *user, char *pass, char *data)
-{
-       DH *dh;
-       char *response, *ret = NULL;
-       unsigned char *secret;
-       unsigned char *encrypted_pass;
-       char *plain_pass;
-       BF_KEY key;
-       int key_size, length;
-       int pass_len = strlen (pass) + (8 - (strlen (pass) % 8));
-       int user_len = strlen (user);
-       guint16 size16;
-       char *in_ptr, *out_ptr;
-
-       if (!parse_dh (data, &dh, &secret, &key_size))
-               return NULL;
-       BF_set_key (&key, key_size, secret);
-
-       encrypted_pass = g_malloc0 (pass_len);
-       plain_pass = g_malloc0 (pass_len);
-       memcpy (plain_pass, pass, strlen(pass));
-       out_ptr = (char*)encrypted_pass;
-       in_ptr = (char*)plain_pass;
-
-       for (length = pass_len; length; length -= 8, in_ptr += 8, out_ptr += 8)
-               BF_ecb_encrypt ((unsigned char*)in_ptr, (unsigned char*)out_ptr, &key, BF_ENCRYPT);
-
-       /* Create response */
-       length = 2 + BN_num_bytes (dh->pub_key) + pass_len + user_len + 1;
-       response = g_malloc0 (length);
-       out_ptr = response;
-
-       /* our key */
-       size16 = htons ((guint16)BN_num_bytes (dh->pub_key));
-       memcpy (out_ptr, &size16, sizeof(size16));
-       out_ptr += 2;
-       BN_bn2bin (dh->pub_key, (guchar*)out_ptr);
-       out_ptr += BN_num_bytes (dh->pub_key);
-
-       /* username */
-       memcpy (out_ptr, user, user_len + 1);
-       out_ptr += user_len + 1;
-
-       /* pass */
-       memcpy (out_ptr, encrypted_pass, pass_len);
-       
-       ret = g_base64_encode ((const guchar*)response, length);
-
-       g_free (response);
-
-       DH_free(dh);
-       g_free (plain_pass);
-       g_free (encrypted_pass);
-       g_free (secret);
-
-       return ret;
-}
-
-char *
-encode_sasl_pass_aes (char *user, char *pass, char *data)
-{
-       DH *dh;
-       AES_KEY key;
-       char *response = NULL;
-       char *out_ptr, *ret = NULL;
-       unsigned char *secret, *ptr;
-       unsigned char *encrypted_userpass, *plain_userpass;
-       int key_size, length;
-       guint16 size16;
-       unsigned char iv[16], iv_copy[16];
-       int user_len = strlen (user) + 1;
-       int pass_len = strlen (pass) + 1;
-       int len = user_len + pass_len;
-       int padlen = 16 - (len % 16);
-       int userpass_len = len + padlen;
-
-       if (!parse_dh (data, &dh, &secret, &key_size))
-               return NULL;
-
-       encrypted_userpass = g_malloc0 (userpass_len);
-       plain_userpass = g_malloc0 (userpass_len);
-
-       /* create message */
-       /* format of: <username>\0<password>\0<padding> */
-       ptr = plain_userpass;
-       memcpy (ptr, user, user_len);
-       ptr += user_len;
-       memcpy (ptr, pass, pass_len);
-       ptr += pass_len;
-       if (padlen)
-       {
-               /* Padding */
-               unsigned char randbytes[16];
-               if (!RAND_bytes (randbytes, padlen))
-                       goto end;
-
-               memcpy (ptr, randbytes, padlen);
-       }
-
-       if (!RAND_bytes (iv, sizeof (iv)))
-               goto end;
-
-       memcpy (iv_copy, iv, sizeof(iv));
-
-       /* Encrypt */
-       AES_set_encrypt_key (secret, key_size * 8, &key);
-       AES_cbc_encrypt(plain_userpass, encrypted_userpass, userpass_len, &key, iv_copy, AES_ENCRYPT);
-
-       /* Create response */
-       /* format of:  <size pubkey><pubkey><iv (always 16 bytes)><ciphertext> */
-       length = 2 + key_size + sizeof(iv) + userpass_len;
-       response = g_malloc (length);
-       out_ptr = response;
-
-       /* our key */
-       size16 = htons ((guint16)key_size);
-       memcpy (out_ptr, &size16, sizeof(size16));
-       out_ptr += 2;
-       BN_bn2bin (dh->pub_key, (guchar*)out_ptr);
-       out_ptr += key_size;
-
-       /* iv */
-       memcpy (out_ptr, iv, sizeof(iv));
-       out_ptr += sizeof(iv);
-
-       /* userpass */
-       memcpy (out_ptr, encrypted_userpass, userpass_len);
-       
-       ret = g_base64_encode ((const guchar*)response, length);
-
-end:
-       DH_free (dh);
-       g_free (plain_userpass);
-       g_free (encrypted_userpass);
-       g_free (secret);
-       g_free (response);
-
-       return ret;
-}
-#endif
-
 #ifdef USE_OPENSSL
 static char *
 str_sha256hash (char *string)
index 2c9f790c0933cae642b2d74ec7bbbcdc7efef136..ba31858581a356a927dc2852b51a2a056cfd81b8 100644 (file)
@@ -76,8 +76,6 @@ void canonalize_key (char *key);
 int portable_mode (void);
 int unity_mode (void);
 char *encode_sasl_pass_plain (char *user, char *pass);
-char *encode_sasl_pass_blowfish (char *user, char *pass, char *data);
-char *encode_sasl_pass_aes (char *user, char *pass, char *data);
 char *challengeauth_response (char *username, char *password, char *challenge);
 size_t strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time);
 gsize strftime_utf8 (char *dest, gsize destsize, const char *format, time_t time);