documented updates
[gnutls.git] / src / srptool.c
blob90adfc7767232be918f773aa985a1071562e827b
1 /*
2 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
6 * GnuTLS is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuTLS is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <gnutls/gnutls.h>
27 #include <gnutls/crypto.h> /* for random */
29 #include <sys/types.h>
30 #include <sys/stat.h>
32 #ifndef _WIN32
33 #include <pwd.h>
34 #include <unistd.h>
35 #else
36 #include <windows.h>
37 #endif
39 /* Gnulib portability files. */
40 #include <getpass.h>
41 #include <minmax.h>
42 #include <progname.h>
43 #include <version-etc.h>
45 #include <srptool-args.h>
47 /* This may need some rewrite. A lot of stuff which should be here
48 * are in the library, which is not good.
51 int crypt_int (const char *username, const char *passwd, int salt,
52 const char *tpasswd_conf, const char *tpasswd, int uindex);
53 static int read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n,
54 char *str);
55 static int _verify_passwd_int (const char *username, const char *passwd,
56 char *verifier, const char *salt,
57 const gnutls_datum_t * g,
58 const gnutls_datum_t * n);
60 static void
61 print_num (const char *msg, const gnutls_datum_t * num)
63 unsigned int i;
65 printf ("%s:\t", msg);
67 for (i = 0; i < num->size; i++)
69 if (i != 0 && i % 12 == 0)
70 printf ("\n\t");
71 else if (i != 0 && i != num->size)
72 printf (":");
73 printf ("%.2x", num->data[i]);
75 printf ("\n\n");
79 static int
80 generate_create_conf (const char *tpasswd_conf)
82 FILE *fd;
83 char line[5 * 1024];
84 int index = 1;
85 gnutls_datum_t g, n;
86 gnutls_datum_t str_g, str_n;
88 fd = fopen (tpasswd_conf, "w");
89 if (fd == NULL)
91 fprintf (stderr, "Cannot open file '%s'\n", tpasswd_conf);
92 return -1;
95 for (index = 1; index <= 5; index++)
98 if (index == 1)
100 n = gnutls_srp_1024_group_prime;
101 g = gnutls_srp_1024_group_generator;
103 else if (index == 2)
105 n = gnutls_srp_1536_group_prime;
106 g = gnutls_srp_1536_group_generator;
108 else if (index == 3)
110 n = gnutls_srp_2048_group_prime;
111 g = gnutls_srp_2048_group_generator;
113 else if (index == 4)
115 n = gnutls_srp_3072_group_prime;
116 g = gnutls_srp_3072_group_generator;
118 else if (index == 5)
120 n = gnutls_srp_4096_group_prime;
121 g = gnutls_srp_4096_group_generator;
123 else
125 fprintf(stderr, "Unknown index: %d\n", index);
126 return -1;
129 printf ("\nGroup %d, of %d bits:\n", index, n.size * 8);
130 print_num ("Generator", &g);
131 print_num ("Prime", &n);
133 if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0)
135 fprintf (stderr, "Could not encode\n");
136 return -1;
139 if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0)
141 fprintf (stderr, "Could not encode\n");
142 return -1;
145 sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data);
147 gnutls_free (str_n.data);
148 gnutls_free (str_g.data);
150 fwrite (line, 1, strlen (line), fd);
154 fclose (fd);
156 return 0;
160 /* The format of a tpasswd file is:
161 * username:verifier:salt:index
163 * index is the index of the prime-generator pair in tpasswd.conf
165 static int
166 _verify_passwd_int (const char *username, const char *passwd,
167 char *verifier, const char *salt,
168 const gnutls_datum_t * g, const gnutls_datum_t * n)
170 char _salt[1024];
171 gnutls_datum_t tmp, raw_salt, new_verifier;
172 size_t salt_size;
173 char *pos;
175 if (salt == NULL || verifier == NULL)
176 return -1;
178 if (strlen(salt) >= sizeof(_salt))
180 fprintf (stderr, "Too long salt.\n");
181 return -1;
184 /* copy salt, and null terminate after the ':' */
185 strcpy (_salt, salt);
186 pos = strchr (_salt, ':');
187 if (pos != NULL)
188 *pos = 0;
190 /* convert salt to binary. */
191 tmp.data = (void*)_salt;
192 tmp.size = strlen (_salt);
194 if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
196 fprintf (stderr, "Could not decode salt.\n");
197 return -1;
200 if (gnutls_srp_verifier
201 (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
203 fprintf (stderr, "Could not make the verifier\n");
204 return -1;
207 free (raw_salt.data);
209 /* encode the verifier into _salt */
210 salt_size = sizeof (_salt);
211 memset (_salt, 0, salt_size);
212 if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0)
214 fprintf (stderr, "Encoding error\n");
215 return -1;
218 free (new_verifier.data);
220 if (strncmp (verifier, _salt, strlen (_salt)) == 0)
222 fprintf (stderr, "Password verified\n");
223 return 0;
225 else
227 fprintf (stderr, "Password does NOT match\n");
229 return -1;
232 static int
233 filecopy (const char *src, const char *dst)
235 FILE *fd, *fd2;
236 char line[5 * 1024];
237 char *p;
239 fd = fopen (dst, "w");
240 if (fd == NULL)
242 fprintf (stderr, "Cannot open '%s' for write\n", dst);
243 return -1;
246 fd2 = fopen (src, "r");
247 if (fd2 == NULL)
249 /* empty file */
250 fclose (fd);
251 return 0;
254 line[sizeof (line) - 1] = 0;
257 p = fgets (line, sizeof (line) - 1, fd2);
258 if (p == NULL)
259 break;
261 fputs (line, fd);
263 while (1);
265 fclose (fd);
266 fclose (fd2);
268 return 0;
271 /* accepts password file */
272 static int
273 find_strchr (const char *username, const char *file)
275 FILE *fd;
276 char *pos;
277 char line[5 * 1024];
278 unsigned int i;
280 fd = fopen (file, "r");
281 if (fd == NULL)
283 fprintf (stderr, "Cannot open file '%s'\n", file);
284 return -1;
287 while (fgets (line, sizeof (line), fd) != NULL)
289 /* move to first ':' */
290 i = 0;
291 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
293 i++;
295 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
297 /* find the index */
298 pos = strrchr (line, ':');
299 pos++;
300 fclose (fd);
301 return atoi (pos);
305 fclose (fd);
306 return -1;
309 /* Parses the tpasswd files, in order to verify the given
310 * username/password pair.
312 static int
313 verify_passwd (const char *conffile, const char *tpasswd,
314 const char *username, const char *passwd)
316 FILE *fd;
317 char line[5 * 1024];
318 unsigned int i;
319 gnutls_datum_t g, n;
320 int iindex;
321 char *p, *pos;
323 iindex = find_strchr (username, tpasswd);
324 if (iindex == -1)
326 fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
327 return -1;
330 fd = fopen (conffile, "r");
331 if (fd == NULL)
333 fprintf (stderr, "Cannot find %s\n", conffile);
334 return -1;
339 p = fgets (line, sizeof (line) - 1, fd);
341 while (p != NULL && atoi (p) != iindex);
343 if (p == NULL)
345 fprintf (stderr, "Cannot find entry in %s\n", conffile);
346 return -1;
348 line[sizeof (line) - 1] = 0;
350 fclose (fd);
352 if ((iindex = read_conf_values (&g, &n, line)) < 0)
354 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
355 return -1;
358 fd = fopen (tpasswd, "r");
359 if (fd == NULL)
361 fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
362 return -1;
365 while (fgets (line, sizeof (line), fd) != NULL)
367 /* move to first ':'
368 * This is the actual verifier.
370 i = 0;
371 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
373 i++;
375 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
377 char *verifier_pos, *salt_pos;
379 pos = strchr (line, ':');
380 fclose (fd);
381 if (pos == NULL)
383 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
384 return -1;
386 pos++;
387 verifier_pos = pos;
389 /* Move to the salt */
390 pos = strchr (pos, ':');
391 if (pos == NULL)
393 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
394 return -1;
396 pos++;
397 salt_pos = pos;
399 return _verify_passwd_int (username, passwd,
400 verifier_pos, salt_pos, &g, &n);
404 fclose (fd);
405 return -1;
409 #define KPASSWD "/etc/tpasswd"
410 #define KPASSWD_CONF "/etc/tpasswd.conf"
412 static void
413 tls_log_func (int level, const char *str)
415 fprintf (stderr, "|<%d>| %s", level, str);
418 int main (int argc, char **argv)
420 const char *passwd;
421 int salt_size, ret;
422 int optct;
423 const char* fpasswd, *fpasswd_conf;
424 const char* username;
425 #ifndef _WIN32
426 struct passwd *pwd;
427 #endif
429 set_program_name (argv[0]);
431 if ((ret = gnutls_global_init ()) < 0)
433 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
434 exit (1);
437 umask (066);
439 optct = optionProcess( &srptoolOptions, argc, argv);
440 argc -= optct;
441 argv += optct;
443 gnutls_global_set_log_function (tls_log_func);
444 gnutls_global_set_log_level (OPT_VALUE_DEBUG);
446 if (HAVE_OPT(CREATE_CONF))
448 return generate_create_conf (OPT_ARG(CREATE_CONF));
451 if (HAVE_OPT(PASSWD))
452 fpasswd = OPT_ARG(PASSWD);
453 else
454 fpasswd = (char *) KPASSWD;
456 if (HAVE_OPT(PASSWD_CONF))
457 fpasswd_conf = OPT_ARG(PASSWD_CONF);
458 else
459 fpasswd_conf = (char *) KPASSWD_CONF;
461 if (HAVE_OPT(USERNAME))
462 username = OPT_ARG(USERNAME);
463 else
465 #ifndef _WIN32
466 pwd = getpwuid (getuid ());
468 if (pwd == NULL)
470 fprintf (stderr, "No such user\n");
471 return -1;
474 username = pwd->pw_name;
475 #else
476 fprintf (stderr, "Please specify a user\n");
477 return -1;
478 #endif
481 salt_size = 16;
483 passwd = getpass ("Enter password: ");
484 if (passwd == NULL)
486 fprintf (stderr, "Please specify a password\n");
487 return -1;
490 /* not ready yet */
491 if (HAVE_OPT(VERIFY))
493 return verify_passwd (fpasswd_conf, fpasswd,
494 username, passwd);
498 return crypt_int (username, passwd, salt_size,
499 fpasswd_conf, fpasswd, VALUE_OPT_INDEX);
503 static char *
504 _srp_crypt (const char *username, const char *passwd, int salt_size,
505 const gnutls_datum_t * g, const gnutls_datum_t * n)
507 unsigned char salt[128];
508 static char result[1024];
509 gnutls_datum_t dat_salt, txt_salt;
510 gnutls_datum_t verifier, txt_verifier;
512 if ((unsigned) salt_size > sizeof (salt))
513 return NULL;
515 /* generate the salt
517 if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
519 fprintf (stderr, "Could not create nonce\n");
520 return NULL;
523 dat_salt.data = salt;
524 dat_salt.size = salt_size;
526 if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
528 fprintf (stderr, "Error getting verifier\n");
529 return NULL;
532 /* base64 encode the verifier */
533 if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
535 fprintf (stderr, "Error encoding\n");
536 free (verifier.data);
537 return NULL;
540 free (verifier.data);
542 if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
544 fprintf (stderr, "Error encoding\n");
545 return NULL;
548 sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
549 free (txt_salt.data);
550 free (txt_verifier.data);
552 return result;
558 crypt_int (const char *username, const char *passwd, int salt_size,
559 const char *tpasswd_conf, const char *tpasswd, int uindex)
561 FILE *fd;
562 char *cr;
563 gnutls_datum_t g, n;
564 char line[5 * 1024];
565 char *p, *pp;
566 int iindex;
567 char tmpname[1024];
569 fd = fopen (tpasswd_conf, "r");
570 if (fd == NULL)
572 fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
573 return -1;
577 { /* find the specified uindex in file */
578 p = fgets (line, sizeof (line) - 1, fd);
579 iindex = atoi (p);
581 while (p != NULL && iindex != uindex);
583 if (p == NULL)
585 fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
586 return -1;
588 line[sizeof (line) - 1] = 0;
590 fclose (fd);
591 if ((iindex = read_conf_values (&g, &n, line)) < 0)
593 fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
594 return -1;
597 cr = _srp_crypt (username, passwd, salt_size, &g, &n);
598 if (cr == NULL)
600 fprintf (stderr, "Cannot _srp_crypt()...\n");
601 return -1;
603 else
605 /* delete previous entry */
606 struct stat st;
607 FILE *fd2;
608 int put;
610 if (strlen (tpasswd) > sizeof (tmpname) + 5)
612 fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
613 return -1;
615 strcpy (tmpname, tpasswd);
616 strcat (tmpname, ".tmp");
618 if (stat (tmpname, &st) != -1)
620 fprintf (stderr, "file '%s' is locked\n", tpasswd);
621 return -1;
624 if (filecopy (tpasswd, tmpname) != 0)
626 fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
627 return -1;
630 fd = fopen (tpasswd, "w");
631 if (fd == NULL)
633 fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
634 remove (tmpname);
635 return -1;
638 fd2 = fopen (tmpname, "r");
639 if (fd2 == NULL)
641 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
642 remove (tmpname);
643 return -1;
646 put = 0;
649 p = fgets (line, sizeof (line) - 1, fd2);
650 if (p == NULL)
651 break;
653 pp = strchr (line, ':');
654 if (pp == NULL)
655 continue;
657 if (strncmp (p, username,
658 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
660 put = 1;
661 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
663 else
665 fputs (line, fd);
668 while (1);
670 if (put == 0)
672 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
675 fclose (fd);
676 fclose (fd2);
678 remove (tmpname);
683 return 0;
688 /* this function parses tpasswd.conf file. Format is:
689 * int(index):base64(n):base64(g)
691 static int
692 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
694 char *p;
695 int len;
696 int index, ret;
697 gnutls_datum_t dat;
699 index = atoi (str);
701 p = strrchr (str, ':'); /* we have g */
702 if (p == NULL)
704 return -1;
707 *p = '\0';
708 p++;
710 /* read the generator */
711 len = strlen (p);
712 if (p[len - 1] == '\n')
713 len--;
715 dat.data = (void*)p;
716 dat.size = len;
717 ret = gnutls_srp_base64_decode_alloc (&dat, g);
719 if (ret < 0)
721 fprintf (stderr, "Decoding error\n");
722 return -1;
725 /* now go for n - modulo */
726 p = strrchr (str, ':'); /* we have n */
727 if (p == NULL)
729 return -1;
732 *p = '\0';
733 p++;
735 dat.data = (void*)p;
736 dat.size = strlen (p);
738 ret = gnutls_srp_base64_decode_alloc (&dat, n);
740 if (ret < 0)
742 fprintf (stderr, "Decoding error\n");
743 free (g->data);
744 return -1;
747 return index;