summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--lib/gnutls_dh.h1
-rw-r--r--lib/gnutls_dh_primes.c46
-rw-r--r--libextra/auth_srp.c17
-rw-r--r--libextra/auth_srp_passwd.c170
-rw-r--r--libextra/auth_srp_passwd.h3
-rw-r--r--libextra/gnutls_srp.c8
-rw-r--r--src/cli.c2
-rw-r--r--src/tests.c14
9 files changed, 133 insertions, 132 deletions
diff --git a/NEWS b/NEWS
index ec09c70ff5..bba1851d9c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.8.1
+- Improved the SRP support, to prevent attackers guessing the
+ available usernames by brute force.
+
Version 0.8.0 (20/01/2002)
- Added gnutls_x509_extract_dn_string() which returns a
distinguished name in a single string.
diff --git a/lib/gnutls_dh.h b/lib/gnutls_dh.h
index 5a455df188..39b0f43876 100644
--- a/lib/gnutls_dh.h
+++ b/lib/gnutls_dh.h
@@ -24,6 +24,5 @@ MPI gnutls_calc_dh_key( MPI f, MPI x, MPI prime );
int _gnutls_dh_generate_prime(MPI *ret_g, MPI* ret_n, int bits);
void _gnutls_dh_clear_mpis(void);
int _gnutls_dh_calc_mpis(void);
-int _gnutls_get_rnd_srp_params(gnutls_datum *g, gnutls_datum* p, int bits);
extern _gnutls_dh_params _gnutls_dh_default_params;
diff --git a/lib/gnutls_dh_primes.c b/lib/gnutls_dh_primes.c
index 641de737f0..7ef003324e 100644
--- a/lib/gnutls_dh_primes.c
+++ b/lib/gnutls_dh_primes.c
@@ -417,52 +417,6 @@ GNUTLS_MPI gnutls_get_dh_params(gnutls_dh_params dh_primes,
return g;
}
-/* returns g and p, depends on the requested bits.
- * We only support limited key sizes.
- */
-int _gnutls_get_rnd_srp_params(gnutls_datum *g, gnutls_datum* p, int bits)
-{
- int i;
-
- if (_gnutls_dh_default_params == NULL) {
- gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- g->data = p->data = NULL;
- g->size = p->size = 0;
-
- bits = normalize_bits(bits);
-
- i = 0;
- do {
- if (_gnutls_dh_default_params[i].bits == bits) {
- if (_gnutls_set_datum( p, _gnutls_dh_default_params[i].prime.data,
- _gnutls_dh_default_params[i].prime.size) < 0) {
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- if (_gnutls_set_datum( g, _gnutls_dh_default_params[i].generator.data,
- _gnutls_dh_default_params[i].generator.size) < 0) {
- _gnutls_free_datum( p);
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- break;
- }
- i++;
- } while (_gnutls_dh_default_params[i].bits != 0);
-
- if (g->data == NULL || p->data == NULL) {
- gnutls_assert();
- _gnutls_free_datum(g);
- _gnutls_free_datum(p);
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- return 0;
-}
-
/* These should be added in gcrypt.h */
GNUTLS_MPI _gcry_generate_elg_prime(int mode, unsigned pbits,
unsigned qbits, GNUTLS_MPI g,
diff --git a/libextra/auth_srp.c b/libextra/auth_srp.c
index d6bdf1491a..c613ea31d2 100644
--- a/libextra/auth_srp.c
+++ b/libextra/auth_srp.c
@@ -91,18 +91,11 @@ int _gnutls_gen_srp_server_kx(gnutls_session state, opaque ** data)
_gnutls_str_cpy( username, MAX_SRP_USERNAME, state->security_parameters.extensions.srp_username);
- pwd_entry = _gnutls_srp_pwd_read_entry( state, username, &err);
-
- if (pwd_entry == NULL) {
- if (err==0) {
- gnutls_assert();
- /* in order to avoid informing the peer that
- * username does not exist.
- */
- pwd_entry = _gnutls_randomize_pwd_entry();
- } else {
- return GNUTLS_E_SRP_PWD_ERROR;
- }
+ ret = _gnutls_srp_pwd_read_entry( state, username, &pwd_entry);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
}
/* copy from pwd_entry to local variables (actually in state) */
diff --git a/libextra/auth_srp_passwd.c b/libextra/auth_srp_passwd.c
index f5781a0692..22e78d452a 100644
--- a/libextra/auth_srp_passwd.c
+++ b/libextra/auth_srp_passwd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001 Nikos Mavroyanopoulos
+ * Copyright (C) 2001,2003 Nikos Mavroyanopoulos
*
* This file is part of GNUTLS.
*
@@ -177,12 +177,13 @@ int ret;
}
-/* this function opens the tpasswd.conf file
+/* this function opens the tpasswd.conf file and reads the g and n
+ * values. They are put in the entry.
*/
static int pwd_read_conf( const char* pconf_file, SRP_PWD_ENTRY* entry, int index) {
FILE * fd;
char line[2*1024];
- uint i;
+ uint i, len;
char indexstr[10];
sprintf( indexstr, "%d", index); /* Flawfinder: ignore */
@@ -193,13 +194,14 @@ static int pwd_read_conf( const char* pconf_file, SRP_PWD_ENTRY* entry, int inde
return GNUTLS_E_FILE_ERROR;
}
+ len = strlen(indexstr);
while( fgets( line, sizeof(line), fd) != NULL) {
- /* move to first ':' */
+ /* move to first ':' */
i=0;
while( (line[i]!=':') && (line[i]!='\0') && (i < sizeof(line)) ) {
i++;
}
- if (strncmp( indexstr, line, strlen(indexstr)) == 0) {
+ if (strncmp( indexstr, line, (i>len)?i:len) == 0) {
if ((index = pwd_put_values2( entry, line)) >= 0)
return 0;
else {
@@ -211,54 +213,70 @@ static int pwd_read_conf( const char* pconf_file, SRP_PWD_ENTRY* entry, int inde
}
-
-SRP_PWD_ENTRY *_gnutls_srp_pwd_read_entry( gnutls_session state, char* username, int *err) {
+int _gnutls_srp_pwd_read_entry( gnutls_session state, char* username,
+ SRP_PWD_ENTRY** _entry)
+{
const gnutls_srp_server_credentials cred;
FILE * fd;
char line[2*1024];
- uint i, len;
- SRP_PWD_ENTRY * entry;
- int index, pwd_index = 0, ret;
+ uint i, len, ret;
+ int index, pwd_index = 0, last_index;
+ SRP_PWD_ENTRY* entry;
- entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY));
- if (entry==NULL) {
+ *_entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY));
+ if (*_entry==NULL) {
gnutls_assert();
- *err = 1;
- return NULL;
+ return GNUTLS_E_MEMORY_ERROR;
}
+ entry = *_entry;
- *err = 0; /* normal exit */
-
cred = _gnutls_get_cred( state->key, GNUTLS_CRD_SRP, NULL);
if (cred==NULL) {
- *err = 1;
gnutls_assert();
_gnutls_srp_entry_free(entry);
- return NULL;
+ return GNUTLS_E_INSUFICIENT_CREDENTIALS;
}
/* if the callback which sends the parameters is
- * set.
+ * set, use it.
*/
if (cred->pwd_callback != NULL) {
ret = cred->pwd_callback( state, username, &entry->salt,
&entry->v, &entry->g, &entry->n);
+
+ if (ret==1) { /* the user does not exist */
+ if (entry->g.size!=0 && entry->n.size!=0) {
+ ret = _randomize_pwd_entry( entry);
+ if (ret < 0) {
+ _gnutls_srp_entry_free(entry);
+ return ret;
+ }
+ return 0;
+ } else {
+ gnutls_assert();
+ ret = -1; /* error in the callback */
+ }
+ }
if (ret < 0) {
gnutls_assert();
_gnutls_srp_entry_free(entry);
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
-
- return entry;
+
+ return 0;
}
+
+ /* The callback was not set. Proceed.
+ */
if (cred->password_files<=0) {
gnutls_assert();
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
- /* use the callback to select a password file */
+ /* use the callback to select a password file. If set.
+ */
if (state->internals.server_srp_callback!=NULL) {
pwd_index = state->internals.server_srp_callback(
state, (const char**)cred->password_file,
@@ -267,95 +285,113 @@ SRP_PWD_ENTRY *_gnutls_srp_pwd_read_entry( gnutls_session state, char* username,
if (pwd_index < 0) {
gnutls_assert();
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
}
+ /* Open the selected password file.
+ */
fd = fopen( cred->password_file[pwd_index], "r");
if (fd==NULL) {
- *err = 1; /* failed due to critical error */
gnutls_assert();
_gnutls_srp_entry_free(entry);
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
+ last_index = 1; /* a default value */
+
+ len = strlen(username);
while( fgets( line, sizeof(line), fd) != NULL) {
/* move to first ':' */
i=0;
while( (line[i]!=':') && (line[i]!='\0') && (i < sizeof(line)) ) {
i++;
}
- len = strlen(username);
+
if (strncmp( username, line, (i>len)?i:len) == 0) {
- if ((index = pwd_put_values( entry, line)) >= 0)
+ if ((index = pwd_put_values( entry, line)) >= 0) {
+ /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
+ * when the user does not exist.
+ */
+ last_index = index;
if (pwd_read_conf( cred->password_conf_file[pwd_index], entry, index)==0) {
- return entry;
+ return 0;
} else {
+ gnutls_assert();
_gnutls_srp_entry_free(entry);
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
- else {
+ } else {
+ gnutls_assert();
_gnutls_srp_entry_free(entry);
- return NULL;
+ return GNUTLS_E_SRP_PWD_ERROR;
}
}
}
- return NULL;
+
+ /* user was not found. Fake him. Actually read the g,n values from
+ * the last index found and randomize the entry.
+ */
+fprintf(stderr, "username: %s\nindex: %d\n", username, last_index);
+ if (pwd_read_conf( cred->password_conf_file[pwd_index], entry, last_index)==0) {
+ ret = _randomize_pwd_entry( entry);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return ret;
+ }
+ return 0;
+ }
+
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+
}
+
+/* Randomizes the given password entry. It actually sets the verifier
+ * and the salt. Returns 0 on success.
+ */
#define RNDUSER "rnd"
#define RND_SALT_SIZE 17
-SRP_PWD_ENTRY* _gnutls_randomize_pwd_entry() {
+int _randomize_pwd_entry(SRP_PWD_ENTRY* entry) {
int ret;
- SRP_PWD_ENTRY * pwd_entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY));
- if (pwd_entry == NULL) {
- gnutls_assert();
- return NULL;
- }
-
- ret = _gnutls_get_rnd_srp_params( &pwd_entry->g, &pwd_entry->n, 1024);
- if (ret < 0) {
+ if (entry->g.size == 0 || entry->n.size == 0) {
gnutls_assert();
- _gnutls_srp_entry_free( pwd_entry);
- return NULL;
+ return GNUTLS_E_INTERNAL_ERROR;
}
-
- pwd_entry->username = gnutls_malloc(strlen(RNDUSER)+1);
- if (pwd_entry->username == NULL) {
+
+ entry->username = gnutls_strdup(RNDUSER);
+ if (entry->username == NULL) {
gnutls_assert();
- _gnutls_srp_entry_free( pwd_entry);
- return NULL;
+ return GNUTLS_E_MEMORY_ERROR;
}
- _gnutls_str_cpy( pwd_entry->username, MAX_SRP_USERNAME, RNDUSER); /* Flawfinder: ignore */
- pwd_entry->v.data = gnutls_malloc(20);
- pwd_entry->v.size = 20;
- if (pwd_entry->v.data==NULL) {
+ entry->v.data = gnutls_malloc(20);
+ entry->v.size = 20;
+ if (entry->v.data==NULL) {
gnutls_assert();
- _gnutls_srp_entry_free( pwd_entry);
- return NULL;
+ return GNUTLS_E_MEMORY_ERROR;
}
- _gnutls_get_random( pwd_entry->v.data, 20, GNUTLS_WEAK_RANDOM);
+ _gnutls_get_random( entry->v.data, 20, GNUTLS_WEAK_RANDOM);
- pwd_entry->salt.size = RND_SALT_SIZE;
+ entry->salt.size = RND_SALT_SIZE;
- pwd_entry->salt.data = gnutls_malloc(RND_SALT_SIZE);
- if (pwd_entry->salt.data==NULL) {
+ entry->salt.data = gnutls_malloc(RND_SALT_SIZE);
+ if (entry->salt.data==NULL) {
gnutls_assert();
- _gnutls_srp_entry_free( pwd_entry);
- return NULL;
+ return GNUTLS_E_MEMORY_ERROR;
}
- if (_gnutls_get_random(pwd_entry->salt.data, RND_SALT_SIZE, GNUTLS_WEAK_RANDOM) < 0) {
+ if (_gnutls_get_random(entry->salt.data, RND_SALT_SIZE, GNUTLS_WEAK_RANDOM) < 0) {
gnutls_assert();
- _gnutls_srp_entry_free( pwd_entry);
- return NULL;
+ return GNUTLS_E_MEMORY_ERROR;
}
- return pwd_entry;
-
+ return 0;
}
void _gnutls_srp_entry_free( SRP_PWD_ENTRY * entry) {
diff --git a/libextra/auth_srp_passwd.h b/libextra/auth_srp_passwd.h
index 14b17c36f9..93c2692c3e 100644
--- a/libextra/auth_srp_passwd.h
+++ b/libextra/auth_srp_passwd.h
@@ -10,9 +10,8 @@ typedef struct {
} SRP_PWD_ENTRY;
/* this is localy alocated. It should be freed using the provided function */
-SRP_PWD_ENTRY *_gnutls_srp_pwd_read_entry( gnutls_session state, char* username, int* err);
+int _gnutls_srp_pwd_read_entry( gnutls_session state, char* username, SRP_PWD_ENTRY**);
void _gnutls_srp_entry_free( SRP_PWD_ENTRY * entry);
-SRP_PWD_ENTRY* _gnutls_randomize_pwd_entry(void);
int _gnutls_sbase64_encode(uint8 * data, size_t data_size, uint8 ** result);
int _gnutls_sbase64_decode(uint8 * data, size_t data_size, uint8 ** result);
diff --git a/libextra/gnutls_srp.c b/libextra/gnutls_srp.c
index 5e84bb29db..59c955a924 100644
--- a/libextra/gnutls_srp.c
+++ b/libextra/gnutls_srp.c
@@ -534,14 +534,18 @@ void gnutls_srp_server_set_select_function(gnutls_session session,
* gnutls_datum* salt, gnutls_datum *verifier, gnutls_datum* g,
* gnutls_datum* n);
*
- * 'username' contains the actual username.
- *
+ * 'username' contains the actual username.
* The 'salt', 'verifier', 'generator' and 'prime' must be filled
* in using the gnutls_malloc().
*
* In case the callback returned a negative number then gnutls will
* assume that the username does not exist.
*
+ * In order to prevent allowing an attack to guess valid usernames,
+ * if username does not exist, the g, and n values should be filled in
+ * using a random user's parameters. In that case the callback should
+ * return the special value (1).
+ *
* The callback function will only be called once per handshake.
* The callback function should return 0 on success.
* -1 indicates an error.
diff --git a/src/cli.c b/src/cli.c
index 98a9fd6f12..f6f5f00997 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -58,7 +58,7 @@ int crlf;
int quiet = 0;
extern int xml;
-char *srp_passwd;
+char *srp_passwd = NULL;
char *srp_username;
char *pgp_keyfile;
char *pgp_certfile;
diff --git a/src/tests.c b/src/tests.c
index 7d16393126..8b3e590a28 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -32,6 +32,7 @@ extern gnutls_anon_client_credentials anon_cred;
extern gnutls_certificate_credentials xcred;
extern int more_info;
+static int srp = 0;
extern int tls1_ok;
extern int ssl3_ok;
@@ -62,6 +63,11 @@ int ret, alert;
GERR(ret);
}
+ if (srp) {
+ if (ret == GNUTLS_E_DECRYPTION_FAILED)
+ return SUCCEED; /* SRP was detected */
+ }
+
if (ret < 0) return FAILED;
gnutls_session_get_data(session, NULL, &session_data_size);
@@ -152,6 +158,8 @@ static void ADD_PROTOCOL(gnutls_session session, int protocol) {
int test_srp( gnutls_session session) {
+int ret;
+
ADD_ALL_CIPHERS(session);
ADD_ALL_COMP(session);
ADD_ALL_CERTTYPES(session);
@@ -159,10 +167,14 @@ int test_srp( gnutls_session session) {
ADD_ALL_MACS(session);
ADD_KX(session, GNUTLS_KX_SRP);
+ srp = 1;
gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
- return do_handshake( session);
+ ret = do_handshake( session);
+ srp = 0;
+
+ return ret;
}
int test_export( gnutls_session session) {