to-p12 requires the load-certificate and load-privkey.
[gnutls.git] / src / srptool.c
blob8c092940195e849a5f1822e825cd7e1b537bb705
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 <gettext.h>
46 #include <srptool-args.h>
48 /* This may need some rewrite. A lot of stuff which should be here
49 * are in the library, which is not good.
52 int crypt_int (const char *username, const char *passwd, int salt,
53 const char *tpasswd_conf, const char *tpasswd, int uindex);
54 static int read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n,
55 char *str);
56 static int _verify_passwd_int (const char *username, const char *passwd,
57 char *verifier, const char *salt,
58 const gnutls_datum_t * g,
59 const gnutls_datum_t * n);
61 static void
62 print_num (const char *msg, const gnutls_datum_t * num)
64 unsigned int i;
66 printf ("%s:\t", msg);
68 for (i = 0; i < num->size; i++)
70 if (i != 0 && i % 12 == 0)
71 printf ("\n\t");
72 else if (i != 0 && i != num->size)
73 printf (":");
74 printf ("%.2x", num->data[i]);
76 printf ("\n\n");
80 static int
81 generate_create_conf (const char *tpasswd_conf)
83 FILE *fd;
84 char line[5 * 1024];
85 int index = 1;
86 gnutls_datum_t g, n;
87 gnutls_datum_t str_g, str_n;
89 fd = fopen (tpasswd_conf, "w");
90 if (fd == NULL)
92 fprintf (stderr, "Cannot open file '%s'\n", tpasswd_conf);
93 return -1;
96 for (index = 1; index <= 5; index++)
99 if (index == 1)
101 n = gnutls_srp_1024_group_prime;
102 g = gnutls_srp_1024_group_generator;
104 else if (index == 2)
106 n = gnutls_srp_1536_group_prime;
107 g = gnutls_srp_1536_group_generator;
109 else if (index == 3)
111 n = gnutls_srp_2048_group_prime;
112 g = gnutls_srp_2048_group_generator;
114 else if (index == 4)
116 n = gnutls_srp_3072_group_prime;
117 g = gnutls_srp_3072_group_generator;
119 else if (index == 5)
121 n = gnutls_srp_4096_group_prime;
122 g = gnutls_srp_4096_group_generator;
124 else
126 fprintf(stderr, "Unknown index: %d\n", index);
127 return -1;
130 printf ("\nGroup %d, of %d bits:\n", index, n.size * 8);
131 print_num ("Generator", &g);
132 print_num ("Prime", &n);
134 if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0)
136 fprintf (stderr, "Could not encode\n");
137 return -1;
140 if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0)
142 fprintf (stderr, "Could not encode\n");
143 return -1;
146 sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data);
148 gnutls_free (str_n.data);
149 gnutls_free (str_g.data);
151 fwrite (line, 1, strlen (line), fd);
155 fclose (fd);
157 return 0;
161 /* The format of a tpasswd file is:
162 * username:verifier:salt:index
164 * index is the index of the prime-generator pair in tpasswd.conf
166 static int
167 _verify_passwd_int (const char *username, const char *passwd,
168 char *verifier, const char *salt,
169 const gnutls_datum_t * g, const gnutls_datum_t * n)
171 char _salt[1024];
172 gnutls_datum_t tmp, raw_salt, new_verifier;
173 size_t salt_size;
174 char *pos;
176 if (salt == NULL || verifier == NULL)
177 return -1;
179 if (strlen(salt) >= sizeof(_salt))
181 fprintf (stderr, "Too long salt.\n");
182 return -1;
185 /* copy salt, and null terminate after the ':' */
186 strcpy (_salt, salt);
187 pos = strchr (_salt, ':');
188 if (pos != NULL)
189 *pos = 0;
191 /* convert salt to binary. */
192 tmp.data = (void*)_salt;
193 tmp.size = strlen (_salt);
195 if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
197 fprintf (stderr, "Could not decode salt.\n");
198 return -1;
201 if (gnutls_srp_verifier
202 (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
204 fprintf (stderr, "Could not make the verifier\n");
205 return -1;
208 free (raw_salt.data);
210 /* encode the verifier into _salt */
211 salt_size = sizeof (_salt);
212 memset (_salt, 0, salt_size);
213 if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0)
215 fprintf (stderr, "Encoding error\n");
216 return -1;
219 free (new_verifier.data);
221 if (strncmp (verifier, _salt, strlen (_salt)) == 0)
223 fprintf (stderr, "Password verified\n");
224 return 0;
226 else
228 fprintf (stderr, "Password does NOT match\n");
230 return -1;
233 static int
234 filecopy (const char *src, const char *dst)
236 FILE *fd, *fd2;
237 char line[5 * 1024];
238 char *p;
240 fd = fopen (dst, "w");
241 if (fd == NULL)
243 fprintf (stderr, "Cannot open '%s' for write\n", dst);
244 return -1;
247 fd2 = fopen (src, "r");
248 if (fd2 == NULL)
250 /* empty file */
251 fclose (fd);
252 return 0;
255 line[sizeof (line) - 1] = 0;
258 p = fgets (line, sizeof (line) - 1, fd2);
259 if (p == NULL)
260 break;
262 fputs (line, fd);
264 while (1);
266 fclose (fd);
267 fclose (fd2);
269 return 0;
272 /* accepts password file */
273 static int
274 find_strchr (const char *username, const char *file)
276 FILE *fd;
277 char *pos;
278 char line[5 * 1024];
279 unsigned int i;
281 fd = fopen (file, "r");
282 if (fd == NULL)
284 fprintf (stderr, "Cannot open file '%s'\n", file);
285 return -1;
288 while (fgets (line, sizeof (line), fd) != NULL)
290 /* move to first ':' */
291 i = 0;
292 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
294 i++;
296 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
298 /* find the index */
299 pos = strrchr (line, ':');
300 pos++;
301 fclose (fd);
302 return atoi (pos);
306 fclose (fd);
307 return -1;
310 /* Parses the tpasswd files, in order to verify the given
311 * username/password pair.
313 static int
314 verify_passwd (const char *conffile, const char *tpasswd,
315 const char *username, const char *passwd)
317 FILE *fd;
318 char line[5 * 1024];
319 unsigned int i;
320 gnutls_datum_t g, n;
321 int iindex;
322 char *p, *pos;
324 iindex = find_strchr (username, tpasswd);
325 if (iindex == -1)
327 fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
328 return -1;
331 fd = fopen (conffile, "r");
332 if (fd == NULL)
334 fprintf (stderr, "Cannot find %s\n", conffile);
335 return -1;
340 p = fgets (line, sizeof (line) - 1, fd);
342 while (p != NULL && atoi (p) != iindex);
344 if (p == NULL)
346 fprintf (stderr, "Cannot find entry in %s\n", conffile);
347 return -1;
349 line[sizeof (line) - 1] = 0;
351 fclose (fd);
353 if ((iindex = read_conf_values (&g, &n, line)) < 0)
355 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
356 return -1;
359 fd = fopen (tpasswd, "r");
360 if (fd == NULL)
362 fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
363 return -1;
366 while (fgets (line, sizeof (line), fd) != NULL)
368 /* move to first ':'
369 * This is the actual verifier.
371 i = 0;
372 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
374 i++;
376 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
378 char *verifier_pos, *salt_pos;
380 pos = strchr (line, ':');
381 fclose (fd);
382 if (pos == NULL)
384 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
385 return -1;
387 pos++;
388 verifier_pos = pos;
390 /* Move to the salt */
391 pos = strchr (pos, ':');
392 if (pos == NULL)
394 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
395 return -1;
397 pos++;
398 salt_pos = pos;
400 return _verify_passwd_int (username, passwd,
401 verifier_pos, salt_pos, &g, &n);
405 fclose (fd);
406 return -1;
410 #define KPASSWD "/etc/tpasswd"
411 #define KPASSWD_CONF "/etc/tpasswd.conf"
413 static void
414 tls_log_func (int level, const char *str)
416 fprintf (stderr, "|<%d>| %s", level, str);
419 int main (int argc, char **argv)
421 const char *passwd;
422 int salt_size, ret;
423 int optct;
424 const char* fpasswd, *fpasswd_conf;
425 const char* username;
426 #ifndef _WIN32
427 struct passwd *pwd;
428 #endif
430 set_program_name (argv[0]);
432 if ((ret = gnutls_global_init ()) < 0)
434 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
435 exit (1);
438 umask (066);
440 optct = optionProcess( &srptoolOptions, argc, argv);
441 argc -= optct;
442 argv += optct;
444 gnutls_global_set_log_function (tls_log_func);
445 gnutls_global_set_log_level (OPT_VALUE_DEBUG);
447 if (HAVE_OPT(CREATE_CONF))
449 return generate_create_conf (OPT_ARG(CREATE_CONF));
452 if (HAVE_OPT(PASSWD))
453 fpasswd = OPT_ARG(PASSWD);
454 else
455 fpasswd = (char *) KPASSWD;
457 if (HAVE_OPT(PASSWD_CONF))
458 fpasswd_conf = OPT_ARG(PASSWD_CONF);
459 else
460 fpasswd_conf = (char *) KPASSWD_CONF;
462 if (HAVE_OPT(USERNAME))
463 username = OPT_ARG(USERNAME);
464 else
466 #ifndef _WIN32
467 pwd = getpwuid (getuid ());
469 if (pwd == NULL)
471 fprintf (stderr, "No such user\n");
472 return -1;
475 username = pwd->pw_name;
476 #else
477 fprintf (stderr, "Please specify a user\n");
478 return -1;
479 #endif
482 salt_size = 16;
484 passwd = getpass ("Enter password: ");
485 if (passwd == NULL)
487 fprintf (stderr, "Please specify a password\n");
488 return -1;
491 /* not ready yet */
492 if (HAVE_OPT(VERIFY))
494 return verify_passwd (fpasswd_conf, fpasswd,
495 username, passwd);
499 return crypt_int (username, passwd, salt_size,
500 fpasswd_conf, fpasswd, VALUE_OPT_INDEX);
504 static char *
505 _srp_crypt (const char *username, const char *passwd, int salt_size,
506 const gnutls_datum_t * g, const gnutls_datum_t * n)
508 unsigned char salt[128];
509 static char result[1024];
510 gnutls_datum_t dat_salt, txt_salt;
511 gnutls_datum_t verifier, txt_verifier;
513 if ((unsigned) salt_size > sizeof (salt))
514 return NULL;
516 /* generate the salt
518 if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
520 fprintf (stderr, "Could not create nonce\n");
521 return NULL;
524 dat_salt.data = salt;
525 dat_salt.size = salt_size;
527 if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
529 fprintf (stderr, "Error getting verifier\n");
530 return NULL;
533 /* base64 encode the verifier */
534 if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
536 fprintf (stderr, "Error encoding\n");
537 free (verifier.data);
538 return NULL;
541 free (verifier.data);
543 if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
545 fprintf (stderr, "Error encoding\n");
546 return NULL;
549 sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
550 free (txt_salt.data);
551 free (txt_verifier.data);
553 return result;
559 crypt_int (const char *username, const char *passwd, int salt_size,
560 const char *tpasswd_conf, const char *tpasswd, int uindex)
562 FILE *fd;
563 char *cr;
564 gnutls_datum_t g, n;
565 char line[5 * 1024];
566 char *p, *pp;
567 int iindex;
568 char tmpname[1024];
570 fd = fopen (tpasswd_conf, "r");
571 if (fd == NULL)
573 fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
574 return -1;
578 { /* find the specified uindex in file */
579 p = fgets (line, sizeof (line) - 1, fd);
580 iindex = atoi (p);
582 while (p != NULL && iindex != uindex);
584 if (p == NULL)
586 fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
587 return -1;
589 line[sizeof (line) - 1] = 0;
591 fclose (fd);
592 if ((iindex = read_conf_values (&g, &n, line)) < 0)
594 fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
595 return -1;
598 cr = _srp_crypt (username, passwd, salt_size, &g, &n);
599 if (cr == NULL)
601 fprintf (stderr, "Cannot _srp_crypt()...\n");
602 return -1;
604 else
606 /* delete previous entry */
607 struct stat st;
608 FILE *fd2;
609 int put;
611 if (strlen (tpasswd) > sizeof (tmpname) + 5)
613 fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
614 return -1;
616 strcpy (tmpname, tpasswd);
617 strcat (tmpname, ".tmp");
619 if (stat (tmpname, &st) != -1)
621 fprintf (stderr, "file '%s' is locked\n", tpasswd);
622 return -1;
625 if (filecopy (tpasswd, tmpname) != 0)
627 fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
628 return -1;
631 fd = fopen (tpasswd, "w");
632 if (fd == NULL)
634 fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
635 remove (tmpname);
636 return -1;
639 fd2 = fopen (tmpname, "r");
640 if (fd2 == NULL)
642 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
643 remove (tmpname);
644 return -1;
647 put = 0;
650 p = fgets (line, sizeof (line) - 1, fd2);
651 if (p == NULL)
652 break;
654 pp = strchr (line, ':');
655 if (pp == NULL)
656 continue;
658 if (strncmp (p, username,
659 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
661 put = 1;
662 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
664 else
666 fputs (line, fd);
669 while (1);
671 if (put == 0)
673 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
676 fclose (fd);
677 fclose (fd2);
679 remove (tmpname);
684 return 0;
689 /* this function parses tpasswd.conf file. Format is:
690 * int(index):base64(n):base64(g)
692 static int
693 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
695 char *p;
696 int len;
697 int index, ret;
698 gnutls_datum_t dat;
700 index = atoi (str);
702 p = strrchr (str, ':'); /* we have g */
703 if (p == NULL)
705 return -1;
708 *p = '\0';
709 p++;
711 /* read the generator */
712 len = strlen (p);
713 if (p[len - 1] == '\n')
714 len--;
716 dat.data = (void*)p;
717 dat.size = len;
718 ret = gnutls_srp_base64_decode_alloc (&dat, g);
720 if (ret < 0)
722 fprintf (stderr, "Decoding error\n");
723 return -1;
726 /* now go for n - modulo */
727 p = strrchr (str, ':'); /* we have n */
728 if (p == NULL)
730 return -1;
733 *p = '\0';
734 p++;
736 dat.data = (void*)p;
737 dat.size = strlen (p);
739 ret = gnutls_srp_base64_decode_alloc (&dat, n);
741 if (ret < 0)
743 fprintf (stderr, "Decoding error\n");
744 free (g->data);
745 return -1;
748 return index;
751 extern void srptool_version (void);
753 void
754 srptool_version (void)
756 const char *p = PACKAGE_NAME;
757 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
758 p = PACKAGE_STRING;
759 version_etc (stdout, "srptool", p, gnutls_check_version (NULL),
760 "Nikos Mavrogiannopoulos", (char *) NULL);