From eac2469275713316e7828616cab2167a5026d117 Mon Sep 17 00:00:00 2001 From: Edoardo Spadolini Date: Fri, 26 Dec 2014 10:19:42 +0100 Subject: [PATCH 1/2] Remove DH-BLOWFISH and DH-AES from the sasl module --- modules/sasl.cpp | 288 +---------------------------------------------- 1 file changed, 1 insertion(+), 287 deletions(-) diff --git a/modules/sasl.cpp b/modules/sasl.cpp index ef6763b2..a556dc1a 100644 --- a/modules/sasl.cpp +++ b/modules/sasl.cpp @@ -17,20 +17,12 @@ #include #include -#ifdef HAVE_LIBSSL -#define HAVE_SASL_MECHANISM -#endif - static const struct { const char *szName; const char *szDescription; const bool bDefault; } SupportedMechanisms[] = { { "EXTERNAL", "TLS certificate, for use with the *cert module", false }, -#ifdef HAVE_SASL_MECHANISM - { "DH-BLOWFISH", "Negotiation using the DH-BLOWFISH mechanism", false }, - { "DH-AES", "Negotiation using the DH-AES mechanism", false }, -#endif { "PLAIN", "Plain text negotiation, this should work always if the network supports SASL", true }, { NULL, NULL, false } }; @@ -72,132 +64,13 @@ private: unsigned int m_uiIndex; }; -#ifdef HAVE_SASL_MECHANISM -class DHCommon { -public: - DH *dh; - unsigned char *secret; - int key_size; - - DHCommon() { - dh = DH_new(); - secret = NULL; - key_size = 0; - } - - ~DHCommon() { - if (dh) - DH_free(dh); - if (secret) - free(secret); - } - - bool ParseDH(const CString &sLine) { - /* - * sLine contains the prime, generator and public key of the server. - * We first extract this information and then we pass this to OpenSSL. - * OpenSSL will generate our own public and private key. Which we then - * use to encrypt our password - * - * sLine will look something like: - * - * base64( - * prime length (2 bytes) - * prime - * generator length (2 bytes) - * generator - * servers public key length (2 bytes) - * servers public key - * ) - */ - - /* Decode base64 into (data, length) */ - CString sData = sLine.Base64Decode_n(); - const unsigned char *data = (const unsigned char*)sData.c_str(); - CString::size_type length = sLine.size(); - - if (length < 2) { - DEBUG("sasl: No prime number"); - return false; - } - - /* Prime number */ - uint16_t size16; - memcpy(&size16, data, sizeof(size16)); - unsigned int size = ntohs(size16); - data += 2; - length -= 2; - - if (size > length) { - DEBUG("sasl: Extracting prime number. Invalid length"); - return false; - } - - dh->p = BN_bin2bn(data, size, NULL); - data += size; - - /* Generator */ - if (length < 2) { - DEBUG("sasl: No generator"); - return false; - } - - memcpy(&size16, data, sizeof(size16)); - size = ntohs(size16); - data += 2; - length -= 2; - - if (size > length) { - DEBUG("sasl: Extracting generator. Invalid length"); - return false; - } - - dh->g = BN_bin2bn(data, size, NULL); - data += size; - - /* Server public key */ - if (length < 2) { - DEBUG("sasl: No public key"); - return false; - } - - memcpy(&size16, data, sizeof(size16)); - size = ntohs(size16); - data += 2; - length -= 2; - - if (size > length) { - DEBUG("sasl: Extracting server public key. Invalid length"); - return false; - } - - BIGNUM *server_pub_key = BN_bin2bn(data, size, NULL); - - /* Generate our own public/private keys */ - if (!DH_generate_key(dh)) { - DEBUG("sasl: Failed to generate keys"); - return false; - } - - /* Compute shared secret */ - secret = (unsigned char*)malloc(DH_size(dh)); - if ((key_size = DH_compute_key(secret, server_pub_key, dh)) == -1) { - DEBUG("sasl: Failed to compute shared secret"); - return false; - } - - return true; - } -}; -#endif - class CSASLMod : public CModule { public: MODCONSTRUCTOR(CSASLMod) { AddCommand("Help", static_cast(&CSASLMod::PrintHelp), "search", "Generate this output"); AddCommand("Set", static_cast(&CSASLMod::Set), - "username password", "Set the password for DH-BLOWFISH/DH-AES/PLAIN"); + "username password", "Set the password for PLAIN"); AddCommand("Mechanism", static_cast(&CSASLMod::SetMechanismCommand), "[mechanism[ ...]]", "Set the mechanisms to be attempted (in order)"); AddCommand("RequireAuth", static_cast(&CSASLMod::RequireAuthCommand), @@ -304,170 +177,11 @@ public: return false; } -#ifdef HAVE_SASL_MECHANISM - bool AuthenticateAES(const CString& sLine) { - CString::size_type length; - - DHCommon dh; - if (!dh.ParseDH(sLine)) - return false; - - const int len = GetNV("username").size() + GetNV("password").size() + 2; - const int padlen = 16 - (len % 16); - CString::size_type userpass_length = len + padlen; - unsigned char *encrypted_userpass = (unsigned char *)malloc(userpass_length); - unsigned char *plaintext_userpass = (unsigned char *)malloc(userpass_length); - - memset(encrypted_userpass, 0, userpass_length); - - /* Create plaintext message */ - unsigned char *ptr = plaintext_userpass; - memcpy(ptr, GetNV("username").c_str(), GetNV("username").size() + 1); - ptr += GetNV("username").size() + 1; - memcpy(ptr, GetNV("password").c_str(), GetNV("password").size() + 1); - ptr += GetNV("password").size() + 1; - if (padlen) - { - /* Padding */ - unsigned char randbytes[16]; - if (!RAND_bytes(randbytes, padlen)) { - DEBUG("sasl: DH-AES: Unable to pad"); - free(encrypted_userpass); - free(plaintext_userpass); - return false; - } - memcpy(ptr, randbytes, padlen); - } - - /* Create the IV - * It is changed during encryption for some reason - so we need to keep a copy. - */ - unsigned char iv[16], iv_copy[16]; - if (!RAND_bytes(iv, sizeof (iv))) { - DEBUG("sasl: DH-AES: Unable to create IV"); - free(encrypted_userpass); - free(plaintext_userpass); - return false; - } - memcpy(iv_copy, iv, sizeof(iv)); - - /* Encrypt */ - AES_KEY key; - AES_set_encrypt_key(dh.secret, dh.key_size * 8, &key); - AES_cbc_encrypt(plaintext_userpass, encrypted_userpass, userpass_length, - &key, iv_copy, AES_ENCRYPT); - - free(plaintext_userpass); - - /* Build our response */ - length = 2 + dh.key_size + sizeof(iv) + userpass_length; - char *response = (char *)malloc(length); - char *out_ptr = response; - - /* Size of the key + key */ - uint16_t size16 = htons((uint16_t)dh.key_size); - memcpy(out_ptr, &size16, sizeof(size16)); - out_ptr += 2; - BN_bn2bin(dh.dh->pub_key, (unsigned char *)out_ptr); - out_ptr += dh.key_size; - - /* Add the IV */ - memcpy(out_ptr, iv, sizeof(iv)); - out_ptr += sizeof(iv); - - /* Add encrypted userpass to the response */ - memcpy(out_ptr, encrypted_userpass, userpass_length); - free(encrypted_userpass); - - PutIRC("AUTHENTICATE " + CString((const char *)response, length).Base64Encode_n()); - - DEBUG(CString((const char *)response, length).Base64Encode_n()); - - free(response); - return true; - } - - bool AuthenticateBlowfish(const CString& sLine) { - /* Encrypt our sasl password with blowfish - * - * Our response should look something like: - * - * base64( - * our public key length (2 bytes) - * our public key - * sasl username + \0 - * blowfish( - * sasl password - * ) - * ) - */ - CString::size_type length; - - /* Our DH params */ - DHCommon dh; - if (!dh.ParseDH(sLine)) - return false; - - // TODO for passwords with length 8, 16, 24, 32, etc. this will have 8 additional zero bytes at the end... - // But it works when treated as null-terminated string anyway, and if it works I don't want to touch it right now. - CString::size_type password_length = GetNV("password").size() + (8 - (GetNV("password").size() % 8)); - unsigned char *encrypted_password = (unsigned char *)malloc(password_length); - char *plaintext_password = (char *)malloc(password_length); - - memset(encrypted_password, 0, password_length); - memset(plaintext_password, 0, password_length); - memcpy(plaintext_password, GetNV("password").c_str(), GetNV("password").size()); - - BF_KEY key; - BF_set_key(&key, dh.key_size, dh.secret); - - char *out_ptr = (char *)encrypted_password; - char *in_ptr = (char *)plaintext_password; - for (length = password_length; length; length -= 8, in_ptr += 8, out_ptr += 8) { - BF_ecb_encrypt((unsigned char *)in_ptr, (unsigned char *)out_ptr, &key, BF_ENCRYPT); - } - - free(plaintext_password); - - /* Build our response */ - length = 2 + BN_num_bytes(dh.dh->pub_key) + password_length + GetNV("username").size() + 1; - char *response = (char *)malloc(length); - out_ptr = response; - - /* Add our key to the response */ - uint16_t size16 = htons((uint16_t)BN_num_bytes(dh.dh->pub_key)); - memcpy(out_ptr, &size16, sizeof(size16)); - out_ptr += 2; - BN_bn2bin(dh.dh->pub_key, (unsigned char *)out_ptr); - out_ptr += BN_num_bytes(dh.dh->pub_key); - - /* Add sasl username to response */ - memcpy(out_ptr, GetNV("username").c_str(), GetNV("username").length() + 1); // +1 for zero byte in the end - out_ptr += GetNV("username").length() + 1; - - /* Finally add the encrypted password to the response */ - memcpy(out_ptr, encrypted_password, password_length); - free(encrypted_password); - - /* Base 64 encode and send! */ - PutIRC("AUTHENTICATE " + CString((const char *)response, length).Base64Encode_n()); - - free(response); - return true; - } -#endif - void Authenticate(const CString& sLine) { if (m_Mechanisms.GetCurrent().Equals("PLAIN") && sLine.Equals("+")) { CString sAuthLine = GetNV("username") + '\0' + GetNV("username") + '\0' + GetNV("password"); sAuthLine.Base64Encode(); PutIRC("AUTHENTICATE " + sAuthLine); -#ifdef HAVE_SASL_MECHANISM - } else if (m_Mechanisms.GetCurrent().Equals("DH-BLOWFISH")) { - AuthenticateBlowfish(sLine); - } else if (m_Mechanisms.GetCurrent().Equals("DH-AES")) { - AuthenticateAES(sLine); -#endif } else { /* Send blank authenticate for other mechanisms (like EXTERNAL). */ PutIRC("AUTHENTICATE +"); From beee1f74bc74b63f911a80a1d7f9736e73f05a26 Mon Sep 17 00:00:00 2001 From: Edoardo Spadolini Date: Fri, 26 Dec 2014 10:30:35 +0100 Subject: [PATCH 2/2] Mention username as well as password in the sasl module help --- modules/sasl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sasl.cpp b/modules/sasl.cpp index a556dc1a..6147643a 100644 --- a/modules/sasl.cpp +++ b/modules/sasl.cpp @@ -70,7 +70,7 @@ public: AddCommand("Help", static_cast(&CSASLMod::PrintHelp), "search", "Generate this output"); AddCommand("Set", static_cast(&CSASLMod::Set), - "username password", "Set the password for PLAIN"); + "username password", "Set username and password for the PLAIN mechanism"); AddCommand("Mechanism", static_cast(&CSASLMod::SetMechanismCommand), "[mechanism[ ...]]", "Set the mechanisms to be attempted (in order)"); AddCommand("RequireAuth", static_cast(&CSASLMod::RequireAuthCommand),