updated libtasn1
[gnutls.git] / lib / auth_srp_passwd.c
blobcd6c7fdbcd46199db769de6c8357d0848555f522
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];
212 int ret;
214 snprintf (indexstr, sizeof(indexstr), "%u", (unsigned int)idx);
216 fd = fopen (pconf_file, "r");
217 if (fd == NULL)
219 gnutls_assert ();
220 return GNUTLS_E_FILE_ERROR;
223 len = strlen (indexstr);
224 while (fgets (line, sizeof (line), fd) != NULL)
226 /* move to first ':' */
227 i = 0;
228 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
230 i++;
232 if (strncmp (indexstr, line, MAX (i, len)) == 0)
234 if ((idx = pwd_put_values2 (entry, line)) >= 0)
236 ret = 0;
237 goto cleanup;
239 else
241 ret = GNUTLS_E_SRP_PWD_ERROR;
242 goto cleanup;
246 ret = GNUTLS_E_SRP_PWD_ERROR;
248 cleanup:
249 fclose(fd);
250 return ret;
255 _gnutls_srp_pwd_read_entry (gnutls_session_t state, char *username,
256 SRP_PWD_ENTRY ** _entry)
258 gnutls_srp_server_credentials_t cred;
259 FILE *fd = NULL;
260 char line[2 * 1024];
261 unsigned i, len;
262 int ret;
263 int idx, last_idx;
264 SRP_PWD_ENTRY *entry = NULL;
266 *_entry = gnutls_calloc (1, sizeof (SRP_PWD_ENTRY));
267 if (*_entry == NULL)
269 gnutls_assert ();
270 return GNUTLS_E_MEMORY_ERROR;
272 entry = *_entry;
274 cred = (gnutls_srp_server_credentials_t)
275 _gnutls_get_cred (state->key, GNUTLS_CRD_SRP, NULL);
276 if (cred == NULL)
278 gnutls_assert ();
279 ret = GNUTLS_E_INSUFFICIENT_CREDENTIALS;
280 goto cleanup;
283 /* if the callback which sends the parameters is
284 * set, use it.
286 if (cred->pwd_callback != NULL)
288 ret = cred->pwd_callback (state, username, &entry->salt,
289 &entry->v, &entry->g, &entry->n);
291 if (ret == 1)
292 { /* the user does not exist */
293 if (entry->g.size != 0 && entry->n.size != 0)
295 ret = _randomize_pwd_entry (entry);
296 if (ret < 0)
298 gnutls_assert ();
299 goto cleanup;
301 return 0;
303 else
305 gnutls_assert ();
306 ret = -1; /* error in the callback */
310 if (ret < 0)
312 gnutls_assert ();
313 ret = GNUTLS_E_SRP_PWD_ERROR;
314 goto cleanup;
317 return 0;
320 /* The callback was not set. Proceed.
323 if (cred->password_file == NULL)
325 gnutls_assert ();
326 ret = GNUTLS_E_SRP_PWD_ERROR;
327 goto cleanup;
330 /* Open the selected password file.
332 fd = fopen (cred->password_file, "r");
333 if (fd == NULL)
335 gnutls_assert ();
336 ret = GNUTLS_E_SRP_PWD_ERROR;
337 goto cleanup;
340 last_idx = 1; /* a default value */
342 len = strlen (username);
343 while (fgets (line, sizeof (line), fd) != NULL)
345 /* move to first ':' */
346 i = 0;
347 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
349 i++;
352 if (strncmp (username, line, MAX (i, len)) == 0)
354 if ((idx = pwd_put_values (entry, line)) >= 0)
356 /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
357 * when the user does not exist.
359 /* XXX: last_idx will not be read as both if block branches return. */
360 last_idx = idx;
361 if (pwd_read_conf (cred->password_conf_file, entry, idx) == 0)
363 goto found;
365 else
367 gnutls_assert ();
368 ret = GNUTLS_E_SRP_PWD_ERROR;
369 goto cleanup;
372 else
374 gnutls_assert ();
375 ret = GNUTLS_E_SRP_PWD_ERROR;
376 goto cleanup;
381 /* user was not found. Fake him. Actually read the g,n values from
382 * the last index found and randomize the entry.
384 if (pwd_read_conf (cred->password_conf_file, entry, last_idx) == 0)
386 ret = _randomize_pwd_entry (entry);
387 if (ret < 0)
389 gnutls_assert ();
390 goto cleanup;
393 goto found;
396 cleanup:
397 gnutls_assert ();
398 if (fd) fclose(fd);
399 _gnutls_srp_entry_free (entry);
400 return GNUTLS_E_SRP_PWD_ERROR;
402 found:
403 if (fd) fclose(fd);
404 return 0;
407 /* Randomizes the given password entry. It actually sets the verifier
408 * and the salt. Returns 0 on success.
410 static int
411 _randomize_pwd_entry (SRP_PWD_ENTRY * entry)
413 unsigned char rnd;
414 int ret;
416 if (entry->g.size == 0 || entry->n.size == 0)
418 gnutls_assert ();
419 return GNUTLS_E_INTERNAL_ERROR;
422 ret = _gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
423 if (ret < 0)
425 gnutls_assert ();
426 return ret;
429 entry->salt.size = (rnd % 10) + 9;
431 entry->v.data = gnutls_malloc (20);
432 entry->v.size = 20;
433 if (entry->v.data == NULL)
435 gnutls_assert ();
436 return GNUTLS_E_MEMORY_ERROR;
439 ret = _gnutls_rnd (GNUTLS_RND_RANDOM, entry->v.data, 20);
440 if (ret < 0)
442 gnutls_assert ();
443 return ret;
446 entry->salt.data = gnutls_malloc (entry->salt.size);
447 if (entry->salt.data == NULL)
449 gnutls_assert ();
450 return GNUTLS_E_MEMORY_ERROR;
453 ret = _gnutls_rnd (GNUTLS_RND_NONCE, entry->salt.data, entry->salt.size);
454 if (ret < 0)
456 gnutls_assert ();
457 return ret;
460 return 0;
463 /* Free all the entry parameters, except if g and n are
464 * the static ones defined in extra.h
466 void
467 _gnutls_srp_entry_free (SRP_PWD_ENTRY * entry)
469 _gnutls_free_datum (&entry->v);
470 _gnutls_free_datum (&entry->salt);
472 if (entry->g.data != gnutls_srp_1024_group_generator.data)
473 _gnutls_free_datum (&entry->g);
475 if (entry->n.data != gnutls_srp_1024_group_prime.data &&
476 entry->n.data != gnutls_srp_1536_group_prime.data &&
477 entry->n.data != gnutls_srp_2048_group_prime.data)
478 _gnutls_free_datum (&entry->n);
480 gnutls_free (entry->username);
481 gnutls_free (entry);
485 #endif /* ENABLE SRP */