From a903f16c68dbcdf812d2e47e2cc3caff34d99176 Mon Sep 17 00:00:00 2001 From: TingPing Date: Mon, 2 Sep 2013 14:24:37 -0400 Subject: Implement BLOWFISh, AES, and EXTERNAL SASL mechanisms Closes #657 --- src/common/util.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 1 deletion(-) (limited to 'src/common/util.c') diff --git a/src/common/util.c b/src/common/util.c index 52464621..374da6e5 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -58,6 +58,17 @@ #include #endif +/* SASL mechanisms */ +#ifdef USE_OPENSSL +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#endif + #ifndef HAVE_SNPRINTF #define snprintf g_snprintf #endif @@ -1929,7 +1940,7 @@ get_subdirs (const char *path) } char * -encode_sasl_pass (char *user, char *pass) +encode_sasl_pass_plain (char *user, char *pass) { int authlen; char *buffer; @@ -1944,6 +1955,230 @@ encode_sasl_pass (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; + 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 = (unsigned char*)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: + if (decoded_data) + g_free (decoded_data); + return 0; +} + +char * +encode_sasl_pass_blowfish (char *user, char *pass, char *data) +{ + DH *dh; + char *response, *ret; + 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 = (guchar*)malloc (pass_len); + memset (encrypted_pass, 0, pass_len); + plain_pass = (char*)malloc (pass_len); + memset (plain_pass, 0, pass_len); + memcpy (plain_pass, pass, pass_len); + 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 = (char*)malloc (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); + + DH_free (dh); + free (plain_pass); + free (encrypted_pass); + free (secret); + free (response); + + 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 = (guchar*)malloc (userpass_len); + memset (encrypted_userpass, 0, userpass_len); + plain_userpass = (guchar*)malloc (userpass_len); + memset (plain_userpass, 0, userpass_len); + + /* create message */ + /* format of: \0\0 */ + 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: */ + length = 2 + key_size + sizeof(iv) + userpass_len; + response = (char*)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); + free (plain_userpass); + free (encrypted_userpass); + free (secret); + if (response) + free (response); + + return ret; +} +#endif + #ifdef WIN32 int find_font (const char *fontname) -- cgit 1.4.1 From bdb18828e36340c1800a0eec9f4b5edc6ffae2b2 Mon Sep 17 00:00:00 2001 From: TingPing Date: Wed, 4 Sep 2013 17:34:57 -0400 Subject: Disable challangeauth without openssl --- src/common/proto-irc.c | 5 +++-- src/common/util.c | 2 ++ src/fe-gtk/servlistgui.c | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src/common/util.c') diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c index a7260896..250a2937 100644 --- a/src/common/proto-irc.c +++ b/src/common/proto-irc.c @@ -1151,7 +1151,6 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[], case WORDL('N','O','T','I'): { int id = FALSE; /* identified */ - char *response; text = word_eol[4]; if (*text == ':') @@ -1159,9 +1158,10 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[], text++; } +#ifdef USE_OPENSSL if (!strncmp (text, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */ { - response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]); + char *response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]); tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n", CHALLENGEAUTH_NICK, @@ -1172,6 +1172,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[], g_free (response); return; /* omit the CHALLENGE ALGOS message */ } +#endif if (serv->have_idmsg) { diff --git a/src/common/util.c b/src/common/util.c index 374da6e5..9771b1f6 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -2210,6 +2210,7 @@ find_font (const char *fontname) } #endif +#ifdef USE_OPENSSL static char * str_sha256hash (char *string) { @@ -2285,3 +2286,4 @@ challengeauth_response (char *username, char *password, char *challenge) return (char *) digest; } +#endif diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c index 62049bd2..ef5b57cd 100644 --- a/src/fe-gtk/servlistgui.c +++ b/src/fe-gtk/servlistgui.c @@ -120,11 +120,15 @@ static int login_types_conf[] = { LOGIN_DEFAULT, /* default entry - we don't use this but it makes indexing consistent with login_types[] so it's nice */ LOGIN_SASL, +#ifdef USE_OPENSSL LOGIN_SASLEXTERNAL, +#endif LOGIN_PASS, LOGIN_MSG_NICKSERV, LOGIN_NICKSERV, +#ifdef USE_OPENSSL LOGIN_CHALLENGEAUTH, +#endif LOGIN_CUSTOM #if 0 LOGIN_NS, @@ -137,11 +141,15 @@ static const char *login_types[]= { "Default", "SASL (username + password)", +#ifdef USE_OPENSSL "SASL EXTERNAL (cert)", +#endif "Server Password (/PASS password)", "NickServ (/MSG NickServ + password)", "NickServ (/NICKSERV + password)", +#ifdef USE_OPENSSL "Challenge Auth (username + password)", +#endif "Custom... (connect commands)", #if 0 "NickServ (/NS + password)", -- cgit 1.4.1