2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 /* Functions for operating in an SRP passwd file are included here */
27 #include <gnutls_int.h>
32 #include "gnutls_errors.h"
33 #include <auth_srp_passwd.h>
35 #include "gnutls_auth.h"
36 #include "gnutls_srp.h"
37 #include "gnutls_dh.h"
39 #include <gnutls_str.h>
40 #include <gnutls_datum.h>
41 #include <gnutls_num.h>
44 static int _randomize_pwd_entry (SRP_PWD_ENTRY
* entry
);
46 /* this function parses tpasswd.conf file. Format is:
47 * string(username):base64(v):base64(salt):int(index)
50 pwd_put_values (SRP_PWD_ENTRY
* entry
, char *str
)
58 p
= strrchr (str
, ':'); /* we have index */
62 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
72 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
76 p
= strrchr (str
, ':'); /* we have salt */
80 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
88 entry
->salt
.size
= _gnutls_sbase64_decode (p
, len
, &entry
->salt
.data
);
90 if (entry
->salt
.size
<= 0)
93 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
96 /* now go for verifier */
97 p
= strrchr (str
, ':'); /* we have verifier */
100 _gnutls_free_datum (&entry
->salt
);
101 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
108 ret
= _gnutls_sbase64_decode (p
, len
, &verifier
);
112 _gnutls_free_datum (&entry
->salt
);
113 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
117 entry
->v
.data
= verifier
;
118 entry
->v
.size
= verifier_size
;
120 /* now go for username */
123 entry
->username
= gnutls_strdup (str
);
124 if (entry
->username
== NULL
)
126 _gnutls_free_datum (&entry
->salt
);
127 _gnutls_free_datum (&entry
->v
);
129 return GNUTLS_E_MEMORY_ERROR
;
136 /* this function parses tpasswd.conf file. Format is:
137 * int(index):base64(n):int(g)
140 pwd_put_values2 (SRP_PWD_ENTRY
* entry
, char *str
)
147 p
= strrchr (str
, ':'); /* we have g */
151 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
157 /* read the generator */
159 if (p
[len
- 1] == '\n' || p
[len
- 1] == ' ')
161 ret
= _gnutls_sbase64_decode (p
, len
, &tmp
);
166 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
172 /* now go for n - modulo */
173 p
= strrchr (str
, ':'); /* we have n */
176 _gnutls_free_datum (&entry
->g
);
178 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
185 ret
= _gnutls_sbase64_decode (p
, len
, &tmp
);
190 _gnutls_free_datum (&entry
->g
);
191 return GNUTLS_E_SRP_PWD_PARSING_ERROR
;
201 /* this function opens the tpasswd.conf file and reads the g and n
202 * values. They are put in the entry.
205 pwd_read_conf (const char *pconf_file
, SRP_PWD_ENTRY
* entry
, int idx
)
212 sprintf (indexstr
, "%d", idx
); /* Flawfinder: ignore */
214 fd
= fopen (pconf_file
, "r");
218 return GNUTLS_E_FILE_ERROR
;
221 len
= strlen (indexstr
);
222 while (fgets (line
, sizeof (line
), fd
) != NULL
)
224 /* move to first ':' */
226 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
230 if (strncmp (indexstr
, line
, MAX (i
, len
)) == 0)
232 if ((idx
= pwd_put_values2 (entry
, line
)) >= 0)
236 return GNUTLS_E_SRP_PWD_ERROR
;
240 return GNUTLS_E_SRP_PWD_ERROR
;
245 _gnutls_srp_pwd_read_entry (gnutls_session_t state
, char *username
,
246 SRP_PWD_ENTRY
** _entry
)
248 gnutls_srp_server_credentials_t cred
;
254 SRP_PWD_ENTRY
*entry
;
256 *_entry
= gnutls_calloc (1, sizeof (SRP_PWD_ENTRY
));
260 return GNUTLS_E_MEMORY_ERROR
;
264 cred
= (gnutls_srp_server_credentials_t
)
265 _gnutls_get_cred (state
->key
, GNUTLS_CRD_SRP
, NULL
);
269 _gnutls_srp_entry_free (entry
);
270 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
273 /* if the callback which sends the parameters is
276 if (cred
->pwd_callback
!= NULL
)
278 ret
= cred
->pwd_callback (state
, username
, &entry
->salt
,
279 &entry
->v
, &entry
->g
, &entry
->n
);
282 { /* the user does not exist */
283 if (entry
->g
.size
!= 0 && entry
->n
.size
!= 0)
285 ret
= _randomize_pwd_entry (entry
);
289 _gnutls_srp_entry_free (entry
);
297 ret
= -1; /* error in the callback */
304 _gnutls_srp_entry_free (entry
);
305 return GNUTLS_E_SRP_PWD_ERROR
;
311 /* The callback was not set. Proceed.
314 if (cred
->password_file
== NULL
)
317 return GNUTLS_E_SRP_PWD_ERROR
;
320 /* Open the selected password file.
322 fd
= fopen (cred
->password_file
, "r");
326 _gnutls_srp_entry_free (entry
);
327 return GNUTLS_E_SRP_PWD_ERROR
;
330 last_idx
= 1; /* a default value */
332 len
= strlen (username
);
333 while (fgets (line
, sizeof (line
), fd
) != NULL
)
335 /* move to first ':' */
337 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
342 if (strncmp (username
, line
, MAX (i
, len
)) == 0)
344 if ((idx
= pwd_put_values (entry
, line
)) >= 0)
346 /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
347 * when the user does not exist.
349 /* XXX: last_idx will not be read as both if block branches return. */
351 if (pwd_read_conf (cred
->password_conf_file
, entry
, idx
) == 0)
358 _gnutls_srp_entry_free (entry
);
359 return GNUTLS_E_SRP_PWD_ERROR
;
365 _gnutls_srp_entry_free (entry
);
366 return GNUTLS_E_SRP_PWD_ERROR
;
371 /* user was not found. Fake him. Actually read the g,n values from
372 * the last index found and randomize the entry.
374 if (pwd_read_conf (cred
->password_conf_file
, entry
, last_idx
) == 0)
376 ret
= _randomize_pwd_entry (entry
);
380 _gnutls_srp_entry_free (entry
);
388 _gnutls_srp_entry_free (entry
);
389 return GNUTLS_E_SRP_PWD_ERROR
;
393 /* Randomizes the given password entry. It actually sets the verifier
394 * and the salt. Returns 0 on success.
397 _randomize_pwd_entry (SRP_PWD_ENTRY
* entry
)
402 if (entry
->g
.size
== 0 || entry
->n
.size
== 0)
405 return GNUTLS_E_INTERNAL_ERROR
;
408 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, &rnd
, 1);
415 entry
->salt
.size
= (rnd
% 10) + 9;
417 entry
->v
.data
= gnutls_malloc (20);
419 if (entry
->v
.data
== NULL
)
422 return GNUTLS_E_MEMORY_ERROR
;
425 ret
= _gnutls_rnd (GNUTLS_RND_RANDOM
, entry
->v
.data
, 20);
432 entry
->salt
.data
= gnutls_malloc (entry
->salt
.size
);
433 if (entry
->salt
.data
== NULL
)
436 return GNUTLS_E_MEMORY_ERROR
;
439 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, entry
->salt
.data
, entry
->salt
.size
);
449 /* Free all the entry parameters, except if g and n are
450 * the static ones defined in extra.h
453 _gnutls_srp_entry_free (SRP_PWD_ENTRY
* entry
)
455 _gnutls_free_datum (&entry
->v
);
456 _gnutls_free_datum (&entry
->salt
);
458 if (entry
->g
.data
!= gnutls_srp_1024_group_generator
.data
)
459 _gnutls_free_datum (&entry
->g
);
461 if (entry
->n
.data
!= gnutls_srp_1024_group_prime
.data
&&
462 entry
->n
.data
!= gnutls_srp_1536_group_prime
.data
&&
463 entry
->n
.data
!= gnutls_srp_2048_group_prime
.data
)
464 _gnutls_free_datum (&entry
->n
);
466 gnutls_free (entry
->username
);
471 #endif /* ENABLE SRP */