2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2010 Free Software
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 /* Functions for operating in an SRP passwd file are included here */
28 #include <gnutls_int.h>
33 #include "gnutls_errors.h"
34 #include <auth_srp_passwd.h>
36 #include "gnutls_auth.h"
37 #include "gnutls_srp.h"
38 #include "gnutls_dh.h"
40 #include <gnutls_str.h>
41 #include <gnutls_datum.h>
42 #include <gnutls_num.h>
45 static int _randomize_pwd_entry (SRP_PWD_ENTRY
* entry
);
47 /* this function parses tpasswd.conf file. Format is:
48 * string(username):base64(v):base64(salt):int(index)
51 pwd_put_values (SRP_PWD_ENTRY
* entry
, char *str
)
59 p
= strrchr (str
, ':'); /* we have index */
63 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
73 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
77 p
= strrchr (str
, ':'); /* we have salt */
81 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
89 entry
->salt
.size
= _gnutls_sbase64_decode (p
, len
, &entry
->salt
.data
);
91 if (entry
->salt
.size
<= 0)
94 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
97 /* now go for verifier */
98 p
= strrchr (str
, ':'); /* we have verifier */
101 _gnutls_free_datum (&entry
->salt
);
102 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
109 ret
= _gnutls_sbase64_decode (p
, len
, &verifier
);
113 _gnutls_free_datum (&entry
->salt
);
114 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
118 entry
->v
.data
= verifier
;
119 entry
->v
.size
= verifier_size
;
121 /* now go for username */
124 entry
->username
= gnutls_strdup (str
);
125 if (entry
->username
== NULL
)
127 _gnutls_free_datum (&entry
->salt
);
128 _gnutls_free_datum (&entry
->v
);
130 return GNUTLS_E_MEMORY_ERROR
;
137 /* this function parses tpasswd.conf file. Format is:
138 * int(index):base64(n):int(g)
141 pwd_put_values2 (SRP_PWD_ENTRY
* entry
, char *str
)
148 p
= strrchr (str
, ':'); /* we have g */
152 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
158 /* read the generator */
160 if (p
[len
- 1] == '\n' || p
[len
- 1] == ' ')
162 ret
= _gnutls_sbase64_decode (p
, len
, &tmp
);
167 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
173 /* now go for n - modulo */
174 p
= strrchr (str
, ':'); /* we have n */
177 _gnutls_free_datum (&entry
->g
);
179 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
186 ret
= _gnutls_sbase64_decode (p
, len
, &tmp
);
191 _gnutls_free_datum (&entry
->g
);
192 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
202 /* this function opens the tpasswd.conf file and reads the g and n
203 * values. They are put in the entry.
206 pwd_read_conf (const char *pconf_file
, SRP_PWD_ENTRY
* entry
, int idx
)
213 snprintf (indexstr
, sizeof(indexstr
), "%u", (unsigned int)idx
);
215 fd
= fopen (pconf_file
, "r");
219 return GNUTLS_E_FILE_ERROR
;
222 len
= strlen (indexstr
);
223 while (fgets (line
, sizeof (line
), fd
) != NULL
)
225 /* move to first ':' */
227 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
231 if (strncmp (indexstr
, line
, MAX (i
, len
)) == 0)
233 if ((idx
= pwd_put_values2 (entry
, line
)) >= 0)
237 return GNUTLS_E_SRP_PWD_ERROR
;
241 return GNUTLS_E_SRP_PWD_ERROR
;
246 _gnutls_srp_pwd_read_entry (gnutls_session_t state
, char *username
,
247 SRP_PWD_ENTRY
** _entry
)
249 gnutls_srp_server_credentials_t cred
;
255 SRP_PWD_ENTRY
*entry
;
257 *_entry
= gnutls_calloc (1, sizeof (SRP_PWD_ENTRY
));
261 return GNUTLS_E_MEMORY_ERROR
;
265 cred
= (gnutls_srp_server_credentials_t
)
266 _gnutls_get_cred (state
->key
, GNUTLS_CRD_SRP
, NULL
);
270 _gnutls_srp_entry_free (entry
);
271 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
274 /* if the callback which sends the parameters is
277 if (cred
->pwd_callback
!= NULL
)
279 ret
= cred
->pwd_callback (state
, username
, &entry
->salt
,
280 &entry
->v
, &entry
->g
, &entry
->n
);
283 { /* the user does not exist */
284 if (entry
->g
.size
!= 0 && entry
->n
.size
!= 0)
286 ret
= _randomize_pwd_entry (entry
);
290 _gnutls_srp_entry_free (entry
);
298 ret
= -1; /* error in the callback */
305 _gnutls_srp_entry_free (entry
);
306 return GNUTLS_E_SRP_PWD_ERROR
;
312 /* The callback was not set. Proceed.
315 if (cred
->password_file
== NULL
)
318 return GNUTLS_E_SRP_PWD_ERROR
;
321 /* Open the selected password file.
323 fd
= fopen (cred
->password_file
, "r");
327 _gnutls_srp_entry_free (entry
);
328 return GNUTLS_E_SRP_PWD_ERROR
;
331 last_idx
= 1; /* a default value */
333 len
= strlen (username
);
334 while (fgets (line
, sizeof (line
), fd
) != NULL
)
336 /* move to first ':' */
338 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
343 if (strncmp (username
, line
, MAX (i
, len
)) == 0)
345 if ((idx
= pwd_put_values (entry
, line
)) >= 0)
347 /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
348 * when the user does not exist.
350 /* XXX: last_idx will not be read as both if block branches return. */
352 if (pwd_read_conf (cred
->password_conf_file
, entry
, idx
) == 0)
359 _gnutls_srp_entry_free (entry
);
360 return GNUTLS_E_SRP_PWD_ERROR
;
366 _gnutls_srp_entry_free (entry
);
367 return GNUTLS_E_SRP_PWD_ERROR
;
372 /* user was not found. Fake him. Actually read the g,n values from
373 * the last index found and randomize the entry.
375 if (pwd_read_conf (cred
->password_conf_file
, entry
, last_idx
) == 0)
377 ret
= _randomize_pwd_entry (entry
);
381 _gnutls_srp_entry_free (entry
);
389 _gnutls_srp_entry_free (entry
);
390 return GNUTLS_E_SRP_PWD_ERROR
;
394 /* Randomizes the given password entry. It actually sets the verifier
395 * and the salt. Returns 0 on success.
398 _randomize_pwd_entry (SRP_PWD_ENTRY
* entry
)
403 if (entry
->g
.size
== 0 || entry
->n
.size
== 0)
406 return GNUTLS_E_INTERNAL_ERROR
;
409 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, &rnd
, 1);
416 entry
->salt
.size
= (rnd
% 10) + 9;
418 entry
->v
.data
= gnutls_malloc (20);
420 if (entry
->v
.data
== NULL
)
423 return GNUTLS_E_MEMORY_ERROR
;
426 ret
= _gnutls_rnd (GNUTLS_RND_RANDOM
, entry
->v
.data
, 20);
433 entry
->salt
.data
= gnutls_malloc (entry
->salt
.size
);
434 if (entry
->salt
.data
== NULL
)
437 return GNUTLS_E_MEMORY_ERROR
;
440 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, entry
->salt
.data
, entry
->salt
.size
);
450 /* Free all the entry parameters, except if g and n are
451 * the static ones defined in extra.h
454 _gnutls_srp_entry_free (SRP_PWD_ENTRY
* entry
)
456 _gnutls_free_datum (&entry
->v
);
457 _gnutls_free_datum (&entry
->salt
);
459 if (entry
->g
.data
!= gnutls_srp_1024_group_generator
.data
)
460 _gnutls_free_datum (&entry
->g
);
462 if (entry
->n
.data
!= gnutls_srp_1024_group_prime
.data
&&
463 entry
->n
.data
!= gnutls_srp_1536_group_prime
.data
&&
464 entry
->n
.data
!= gnutls_srp_2048_group_prime
.data
)
465 _gnutls_free_datum (&entry
->n
);
467 gnutls_free (entry
->username
);
472 #endif /* ENABLE SRP */