1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-03 16:23:14 +02:00

irc: drop support of DH-BLOWFISH and DH-AES SASL mechanisms (closes #175)

This commit is contained in:
Sébastien Helleu
2021-06-15 21:49:45 +02:00
parent 51740eb21e
commit e8cdda318f
34 changed files with 106 additions and 507 deletions
+2 -6
View File
@@ -1868,13 +1868,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
"\"ecdsa-nist256p-challenge\" for key-based "
"challenge authentication, "
"\"external\" for authentication using client side SSL "
"cert, "
"\"dh-blowfish\" for blowfish crypted password "
"(insecure, not recommended), "
"\"dh-aes\" for AES crypted password "
"(insecure, not recommended)"),
"certificate"),
"plain|scram-sha-1|scram-sha-256|scram-sha-512|"
"ecdsa-nist256p-challenge|external|dh-blowfish|dh-aes",
"ecdsa-nist256p-challenge|external",
0, 0,
default_value, value,
null_value_allowed,
-8
View File
@@ -502,14 +502,6 @@ IRC_PROTOCOL_CALLBACK(authenticate)
case IRC_SASL_MECHANISM_EXTERNAL:
answer = strdup ("+");
break;
case IRC_SASL_MECHANISM_DH_BLOWFISH:
answer = irc_sasl_mechanism_dh_blowfish (
argv[1], sasl_username, sasl_password, &sasl_error);
break;
case IRC_SASL_MECHANISM_DH_AES:
answer = irc_sasl_mechanism_dh_aes (
argv[1], sasl_username, sasl_password, &sasl_error);
break;
}
if (answer)
{
+1 -383
View File
@@ -43,7 +43,7 @@
*/
char *irc_sasl_mechanism_string[IRC_NUM_SASL_MECHANISMS] =
{ "plain", "scram-sha-1", "scram-sha-256", "scram-sha-512",
"ecdsa-nist256p-challenge", "external", "dh-blowfish", "dh-aes" };
"ecdsa-nist256p-challenge", "external" };
/*
@@ -711,385 +711,3 @@ irc_sasl_mechanism_ecdsa_nist256p_challenge (struct t_irc_server *server,
return NULL;
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x030015 */
}
/*
* Reads key sent by server (Diffie-Hellman key exchange).
*
* If an error occurs and if sasl_error is not NULL, *sasl_error is set to the
* error and must be freed after use.
*
* Returns:
* 1: OK
* 0: error
*/
int
irc_sasl_dh (const char *data_base64,
unsigned char **public_bin, unsigned char **secret_bin,
int *length_key, char **sasl_error)
{
char *data;
unsigned char *ptr_data;
int length_data, size, num_bits_prime_number, rc;
size_t num_written;
gcry_mpi_t data_prime_number, data_generator_number, data_server_pub_key;
gcry_mpi_t pub_key, priv_key, secret_mpi;
rc = 0;
data = NULL;
data_prime_number = NULL;
data_generator_number = NULL;
data_server_pub_key = NULL;
pub_key = NULL;
priv_key = NULL;
secret_mpi = NULL;
/* decode data */
data = malloc (strlen (data_base64) + 1);
if (!data)
goto memory_error;
length_data = weechat_string_base_decode (64, data_base64, data);
ptr_data = (unsigned char *)data;
/* extract prime number */
size = ntohs ((((unsigned int)ptr_data[1]) << 8) | ptr_data[0]);
ptr_data += 2;
length_data -= 2;
if (size > length_data)
goto crypto_error;
data_prime_number = gcry_mpi_new (size * 8);
gcry_mpi_scan (&data_prime_number, GCRYMPI_FMT_USG, ptr_data, size, NULL);
num_bits_prime_number = gcry_mpi_get_nbits (data_prime_number);
if (num_bits_prime_number == 0 || INT_MAX - 7 < num_bits_prime_number)
goto crypto_error;
ptr_data += size;
length_data -= size;
/* extract generator number */
size = ntohs ((((unsigned int)ptr_data[1]) << 8) | ptr_data[0]);
ptr_data += 2;
length_data -= 2;
if (size > length_data)
goto crypto_error;
data_generator_number = gcry_mpi_new (size * 8);
gcry_mpi_scan (&data_generator_number, GCRYMPI_FMT_USG, ptr_data, size, NULL);
ptr_data += size;
length_data -= size;
/* extract server-generated public key */
size = ntohs ((((unsigned int)ptr_data[1]) << 8) | ptr_data[0]);
ptr_data += 2;
length_data -= 2;
if (size > length_data)
goto crypto_error;
data_server_pub_key = gcry_mpi_new (size * 8);
gcry_mpi_scan (&data_server_pub_key, GCRYMPI_FMT_USG, ptr_data, size, NULL);
/* generate keys */
pub_key = gcry_mpi_new (num_bits_prime_number);
priv_key = gcry_mpi_new (num_bits_prime_number);
gcry_mpi_randomize (priv_key, num_bits_prime_number, GCRY_STRONG_RANDOM);
/* pub_key = (g ^ priv_key) % p */
gcry_mpi_powm (pub_key, data_generator_number, priv_key, data_prime_number);
/* compute secret_bin */
*length_key = (num_bits_prime_number + 7) / 8;
*secret_bin = malloc (*length_key);
secret_mpi = gcry_mpi_new (num_bits_prime_number);
/* secret_mpi = (y ^ priv_key) % p */
gcry_mpi_powm (secret_mpi, data_server_pub_key, priv_key, data_prime_number);
gcry_mpi_print (GCRYMPI_FMT_USG, *secret_bin, *length_key,
&num_written, secret_mpi);
/* create public_bin */
*public_bin = malloc (*length_key);
gcry_mpi_print (GCRYMPI_FMT_USG, *public_bin, *length_key,
&num_written, pub_key);
rc = 1;
goto end;
memory_error:
if (sasl_error)
*sasl_error = strdup (_("memory error"));
goto end;
crypto_error:
if (sasl_error)
*sasl_error = strdup (_("cryptography error"));
goto end;
end:
if (data)
free (data);
if (data_prime_number)
gcry_mpi_release (data_prime_number);
if (data_generator_number)
gcry_mpi_release (data_generator_number);
if (data_server_pub_key)
gcry_mpi_release (data_server_pub_key);
if (pub_key)
gcry_mpi_release (pub_key);
if (priv_key)
gcry_mpi_release (priv_key);
if (secret_mpi)
gcry_mpi_release (secret_mpi);
return rc;
}
/*
* Builds answer for SASL authentication, using mechanism "DH-BLOWFISH".
*
* Argument data_base64 is a concatenation of 3 strings, each string is composed
* of 2 bytes (length of string), followed by content of string:
* 1. a prime number
* 2. a generator number
* 3. server-generated public key
*
* If an error occurs and if sasl_error is not NULL, *sasl_error is set to the
* error and must be freed after use.
*
* Note: result must be freed after use.
*/
char *
irc_sasl_mechanism_dh_blowfish (const char *data_base64,
const char *sasl_username,
const char *sasl_password,
char **sasl_error)
{
char *answer, *ptr_answer, *answer_base64;
unsigned char *password_clear, *password_crypted;
int length_key, length_username, length_password, length_answer;
unsigned char *public_bin, *secret_bin;
gcry_cipher_hd_t gcrypt_handle;
password_clear = NULL;
password_crypted = NULL;
answer = NULL;
answer_base64 = NULL;
secret_bin = NULL;
public_bin = NULL;
if (!irc_sasl_dh (data_base64, &public_bin, &secret_bin, &length_key,
sasl_error))
{
goto end;
}
/* create password buffers (clear and crypted) */
length_password = strlen (sasl_password) +
((8 - (strlen (sasl_password) % 8)) % 8);
password_clear = calloc (1, length_password);
password_crypted = calloc (1, length_password);
memcpy (password_clear, sasl_password, strlen (sasl_password));
/* crypt password using blowfish */
if (gcry_cipher_open (&gcrypt_handle, GCRY_CIPHER_BLOWFISH,
GCRY_CIPHER_MODE_ECB, 0) != 0)
goto crypto_error;
if (gcry_cipher_setkey (gcrypt_handle, secret_bin, length_key) != 0)
goto crypto_error;
if (gcry_cipher_encrypt (gcrypt_handle,
password_crypted, length_password,
password_clear, length_password) != 0)
goto crypto_error;
gcry_cipher_close (gcrypt_handle);
/*
* build answer for server, it is concatenation of:
* 1. key length (2 bytes)
* 2. public key ('length_key' bytes)
* 3. sasl_username ('length_username'+1 bytes)
* 4. encrypted password ('length_password' bytes)
*/
length_username = strlen (sasl_username) + 1;
length_answer = 2 + length_key + length_username + length_password;
answer = malloc (length_answer);
ptr_answer = answer;
*((unsigned int *)ptr_answer) = htons (length_key);
ptr_answer += 2;
memcpy (ptr_answer, public_bin, length_key);
ptr_answer += length_key;
memcpy (ptr_answer, sasl_username, length_username);
ptr_answer += length_username;
memcpy (ptr_answer, password_crypted, length_password);
/* encode answer to base64 */
answer_base64 = malloc ((length_answer + 1) * 4);
if (answer_base64)
{
if (weechat_string_base_encode (64, answer, length_answer,
answer_base64) < 0)
{
free (answer_base64);
answer_base64 = NULL;
}
}
goto end;
crypto_error:
if (sasl_error)
*sasl_error = strdup (_("cryptography error"));
goto end;
end:
if (secret_bin)
free (secret_bin);
if (public_bin)
free (public_bin);
if (password_clear)
free (password_clear);
if (password_crypted)
free (password_crypted);
if (answer)
free (answer);
return answer_base64;
}
/*
* Builds answer for SASL authentication, using mechanism "DH-AES".
*
* Argument data_base64 is a concatenation of 3 strings, each string is composed
* of 2 bytes (length of string), followed by content of string:
* 1. a prime number
* 2. a generator number
* 3. server-generated public key
*
* If an error occurs and if sasl_error is not NULL, *sasl_error is set to the
* error and must be freed after use.
*
* Note: result must be freed after use.
*/
char *
irc_sasl_mechanism_dh_aes (const char *data_base64,
const char *sasl_username,
const char *sasl_password,
char **sasl_error)
{
char *answer, *ptr_answer, *answer_base64;
unsigned char *ptr_userpass, *userpass_clear, *userpass_crypted;
int length_key, length_answer;
int length_username, length_password, length_userpass;
unsigned char *public_bin, *secret_bin;
char iv[16];
int cipher_algo;
gcry_cipher_hd_t gcrypt_handle;
userpass_clear = NULL;
userpass_crypted = NULL;
answer = NULL;
answer_base64 = NULL;
secret_bin = NULL;
public_bin = NULL;
if (!irc_sasl_dh (data_base64, &public_bin, &secret_bin, &length_key,
sasl_error))
{
goto end;
}
/* Select cipher algorithm: key length * 8 = cipher bit size */
switch (length_key)
{
case 32:
cipher_algo = GCRY_CIPHER_AES256;
break;
case 24:
cipher_algo = GCRY_CIPHER_AES192;
break;
case 16:
cipher_algo = GCRY_CIPHER_AES128;
break;
default:
/* Invalid bit length */
goto end;
}
/* Generate the IV */
gcry_randomize (iv, sizeof (iv), GCRY_STRONG_RANDOM);
/* create user/pass buffers (clear and crypted) */
length_username = strlen (sasl_username) + 1;
length_password = strlen (sasl_password) + 1;
length_userpass = length_username + length_password +
((16 - ((length_username + length_password) % 16)) % 16);
userpass_clear = calloc (1, length_userpass);
ptr_userpass = userpass_clear;
userpass_crypted = calloc (1, length_userpass);
memcpy (ptr_userpass, sasl_username, length_username);
ptr_userpass += length_username;
memcpy (ptr_userpass, sasl_password, length_password);
/* crypt password using AES in CBC mode */
if (gcry_cipher_open (&gcrypt_handle, cipher_algo,
GCRY_CIPHER_MODE_CBC, 0) != 0)
goto crypto_error;
if (gcry_cipher_setkey (gcrypt_handle, secret_bin, length_key) != 0)
goto crypto_error;
if (gcry_cipher_setiv (gcrypt_handle, iv, sizeof (iv)) != 0)
goto crypto_error;
if (gcry_cipher_encrypt (gcrypt_handle,
userpass_crypted, length_userpass,
userpass_clear, length_userpass) != 0)
goto crypto_error;
gcry_cipher_close (gcrypt_handle);
/*
* build answer for server, it is concatenation of:
* 1. key length (2 bytes)
* 2. public key ('length_key' bytes)
* 3. IV (sizeof (iv) bytes)
* 4. encrypted password ('length_userpass' bytes)
*/
length_answer = 2 + length_key + sizeof (iv) + length_userpass;
answer = malloc (length_answer);
ptr_answer = answer;
*((unsigned int *)ptr_answer) = htons (length_key);
ptr_answer += 2;
memcpy (ptr_answer, public_bin, length_key);
ptr_answer += length_key;
memcpy (ptr_answer, iv, sizeof (iv));
ptr_answer += sizeof (iv);
memcpy (ptr_answer, userpass_crypted, length_userpass);
/* encode answer to base64 */
answer_base64 = malloc ((length_answer + 1) * 4);
if (answer_base64)
{
if (weechat_string_base_encode (64, answer, length_answer,
answer_base64) < 0)
{
free (answer_base64);
answer_base64 = NULL;
}
}
goto end;
crypto_error:
if (sasl_error)
*sasl_error = strdup (_("cryptography error"));
goto end;
end:
if (secret_bin)
free (secret_bin);
if (public_bin)
free (public_bin);
if (userpass_clear)
free (userpass_clear);
if (userpass_crypted)
free (userpass_crypted);
if (answer)
free (answer);
return answer_base64;
}
-10
View File
@@ -35,8 +35,6 @@ enum t_irc_sasl_mechanism
IRC_SASL_MECHANISM_SCRAM_SHA_512,
IRC_SASL_MECHANISM_ECDSA_NIST256P_CHALLENGE,
IRC_SASL_MECHANISM_EXTERNAL,
IRC_SASL_MECHANISM_DH_BLOWFISH,
IRC_SASL_MECHANISM_DH_AES,
/* number of SASL mechanisms */
IRC_NUM_SASL_MECHANISMS,
};
@@ -56,13 +54,5 @@ extern char *irc_sasl_mechanism_ecdsa_nist256p_challenge (struct t_irc_server *s
const char *sasl_username,
const char *sasl_key,
char **sasl_error);
extern char *irc_sasl_mechanism_dh_blowfish (const char *data_base64,
const char *sasl_username,
const char *sasl_password,
char **sasl_error);
extern char *irc_sasl_mechanism_dh_aes (const char *data_base64,
const char *sasl_username,
const char *sasl_password,
char **sasl_error);
#endif /* WEECHAT_PLUGIN_IRC_SASL_H */