documented fix
[gnutls.git] / lib / auth_srp_passwd.c
blob370f845243475c19e9ebe25d33a15ad92b6d51be
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2010 Free Software
3 * Foundation, Inc.
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,
22 * USA
26 /* Functions for operating in an SRP passwd file are included here */
28 #include <gnutls_int.h>
30 #ifdef ENABLE_SRP
32 #include "x509_b64.h"
33 #include "gnutls_errors.h"
34 #include <auth_srp_passwd.h>
35 #include "auth_srp.h"
36 #include "gnutls_auth.h"
37 #include "gnutls_srp.h"
38 #include "gnutls_dh.h"
39 #include "debug.h"
40 #include <gnutls_str.h>
41 #include <gnutls_datum.h>
42 #include <gnutls_num.h>
43 #include <random.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)
50 static int
51 pwd_put_values (SRP_PWD_ENTRY * entry, char *str)
53 char *p;
54 int len, ret;
55 opaque *verifier;
56 size_t verifier_size;
57 int indx;
59 p = strrchr (str, ':'); /* we have index */
60 if (p == NULL)
62 gnutls_assert ();
63 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
66 *p = '\0';
67 p++;
69 indx = atoi (p);
70 if (indx == 0)
72 gnutls_assert ();
73 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
76 /* now go for salt */
77 p = strrchr (str, ':'); /* we have salt */
78 if (p == NULL)
80 gnutls_assert ();
81 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
84 *p = '\0';
85 p++;
87 len = strlen (p);
89 entry->salt.size = _gnutls_sbase64_decode (p, len, &entry->salt.data);
91 if (entry->salt.size <= 0)
93 gnutls_assert ();
94 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
97 /* now go for verifier */
98 p = strrchr (str, ':'); /* we have verifier */
99 if (p == NULL)
101 _gnutls_free_datum (&entry->salt);
102 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
105 *p = '\0';
106 p++;
108 len = strlen (p);
109 ret = _gnutls_sbase64_decode (p, len, &verifier);
110 if (ret <= 0)
112 gnutls_assert ();
113 _gnutls_free_datum (&entry->salt);
114 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
117 verifier_size = ret;
118 entry->v.data = verifier;
119 entry->v.size = verifier_size;
121 /* now go for username */
122 *p = '\0';
124 entry->username = gnutls_strdup (str);
125 if (entry->username == NULL)
127 _gnutls_free_datum (&entry->salt);
128 _gnutls_free_datum (&entry->v);
129 gnutls_assert ();
130 return GNUTLS_E_MEMORY_ERROR;
133 return indx;
137 /* this function parses tpasswd.conf file. Format is:
138 * int(index):base64(n):int(g)
140 static int
141 pwd_put_values2 (SRP_PWD_ENTRY * entry, char *str)
143 char *p;
144 int len;
145 opaque *tmp;
146 int ret;
148 p = strrchr (str, ':'); /* we have g */
149 if (p == NULL)
151 gnutls_assert ();
152 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
155 *p = '\0';
156 p++;
158 /* read the generator */
159 len = strlen (p);
160 if (p[len - 1] == '\n' || p[len - 1] == ' ')
161 len--;
162 ret = _gnutls_sbase64_decode (p, len, &tmp);
164 if (ret < 0)
166 gnutls_assert ();
167 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
170 entry->g.data = tmp;
171 entry->g.size = ret;
173 /* now go for n - modulo */
174 p = strrchr (str, ':'); /* we have n */
175 if (p == NULL)
177 _gnutls_free_datum (&entry->g);
178 gnutls_assert ();
179 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
182 *p = '\0';
183 p++;
185 len = strlen (p);
186 ret = _gnutls_sbase64_decode (p, len, &tmp);
188 if (ret < 0)
190 gnutls_assert ();
191 _gnutls_free_datum (&entry->g);
192 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
195 entry->n.data = tmp;
196 entry->n.size = ret;
198 return 0;
202 /* this function opens the tpasswd.conf file and reads the g and n
203 * values. They are put in the entry.
205 static int
206 pwd_read_conf (const char *pconf_file, SRP_PWD_ENTRY * entry, int idx)
208 FILE *fd;
209 char line[2 * 1024];
210 unsigned i, len;
211 char indexstr[10];
213 snprintf (indexstr, sizeof(indexstr), "%u", (unsigned int)idx);
215 fd = fopen (pconf_file, "r");
216 if (fd == NULL)
218 gnutls_assert ();
219 return GNUTLS_E_FILE_ERROR;
222 len = strlen (indexstr);
223 while (fgets (line, sizeof (line), fd) != NULL)
225 /* move to first ':' */
226 i = 0;
227 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
229 i++;
231 if (strncmp (indexstr, line, MAX (i, len)) == 0)
233 if ((idx = pwd_put_values2 (entry, line)) >= 0)
234 return 0;
235 else
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;
250 FILE *fd;
251 char line[2 * 1024];
252 unsigned i, len;
253 int ret;
254 int idx, last_idx;
255 SRP_PWD_ENTRY *entry;
257 *_entry = gnutls_calloc (1, sizeof (SRP_PWD_ENTRY));
258 if (*_entry == NULL)
260 gnutls_assert ();
261 return GNUTLS_E_MEMORY_ERROR;
263 entry = *_entry;
265 cred = (gnutls_srp_server_credentials_t)
266 _gnutls_get_cred (state->key, GNUTLS_CRD_SRP, NULL);
267 if (cred == NULL)
269 gnutls_assert ();
270 _gnutls_srp_entry_free (entry);
271 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
274 /* if the callback which sends the parameters is
275 * set, use it.
277 if (cred->pwd_callback != NULL)
279 ret = cred->pwd_callback (state, username, &entry->salt,
280 &entry->v, &entry->g, &entry->n);
282 if (ret == 1)
283 { /* the user does not exist */
284 if (entry->g.size != 0 && entry->n.size != 0)
286 ret = _randomize_pwd_entry (entry);
287 if (ret < 0)
289 gnutls_assert ();
290 _gnutls_srp_entry_free (entry);
291 return ret;
293 return 0;
295 else
297 gnutls_assert ();
298 ret = -1; /* error in the callback */
302 if (ret < 0)
304 gnutls_assert ();
305 _gnutls_srp_entry_free (entry);
306 return GNUTLS_E_SRP_PWD_ERROR;
309 return 0;
312 /* The callback was not set. Proceed.
315 if (cred->password_file == NULL)
317 gnutls_assert ();
318 return GNUTLS_E_SRP_PWD_ERROR;
321 /* Open the selected password file.
323 fd = fopen (cred->password_file, "r");
324 if (fd == NULL)
326 gnutls_assert ();
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 ':' */
337 i = 0;
338 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
340 i++;
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. */
351 last_idx = idx;
352 if (pwd_read_conf (cred->password_conf_file, entry, idx) == 0)
354 return 0;
356 else
358 gnutls_assert ();
359 _gnutls_srp_entry_free (entry);
360 return GNUTLS_E_SRP_PWD_ERROR;
363 else
365 gnutls_assert ();
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);
378 if (ret < 0)
380 gnutls_assert ();
381 _gnutls_srp_entry_free (entry);
382 return ret;
385 return 0;
388 gnutls_assert ();
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.
397 static int
398 _randomize_pwd_entry (SRP_PWD_ENTRY * entry)
400 unsigned char rnd;
401 int ret;
403 if (entry->g.size == 0 || entry->n.size == 0)
405 gnutls_assert ();
406 return GNUTLS_E_INTERNAL_ERROR;
409 ret = _gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
410 if (ret < 0)
412 gnutls_assert ();
413 return ret;
416 entry->salt.size = (rnd % 10) + 9;
418 entry->v.data = gnutls_malloc (20);
419 entry->v.size = 20;
420 if (entry->v.data == NULL)
422 gnutls_assert ();
423 return GNUTLS_E_MEMORY_ERROR;
426 ret = _gnutls_rnd (GNUTLS_RND_RANDOM, entry->v.data, 20);
427 if (ret < 0)
429 gnutls_assert ();
430 return ret;
433 entry->salt.data = gnutls_malloc (entry->salt.size);
434 if (entry->salt.data == NULL)
436 gnutls_assert ();
437 return GNUTLS_E_MEMORY_ERROR;
440 ret = _gnutls_rnd (GNUTLS_RND_NONCE, entry->salt.data, entry->salt.size);
441 if (ret < 0)
443 gnutls_assert ();
444 return ret;
447 return 0;
450 /* Free all the entry parameters, except if g and n are
451 * the static ones defined in extra.h
453 void
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);
468 gnutls_free (entry);
472 #endif /* ENABLE SRP */