Generated.
[gnutls.git] / src / crypt.c
blob623052b43cd5aec43d9edcb56b396570db2c7640
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Simon Josefsson
3 * Copyright (C) 2001,2003 Nikos Mavrogiannopoulos
4 * Copyright (C) 2004 Free Software Foundation
6 * This file is part of GNUTLS.
8 * GNUTLS is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GNUTLS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <config.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <gnutls/gnutls.h>
28 #include <gnutls/extra.h>
29 #include <crypt-gaa.h>
30 #include "../lib/random.h" /* for random */
32 #include <sys/types.h>
33 #include <sys/stat.h>
35 #ifndef _WIN32
36 # include <pwd.h>
37 # include <unistd.h>
38 #else
39 # include <windows.h>
40 #endif
42 /* Gnulib portability files. */
43 #include <getpass.h>
44 #include <minmax.h>
45 #include <progname.h>
46 #include <version-etc.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 char *tpasswd_conf, 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, 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 (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 <= 3; 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
111 n = gnutls_srp_2048_group_prime;
112 g = gnutls_srp_2048_group_generator;
115 printf ("\nGroup %d, of %d bits:\n", index, n.size * 8);
116 print_num ("Generator", &g);
117 print_num ("Prime", &n);
119 if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0)
121 fprintf (stderr, "Could not encode\n");
122 return -1;
125 if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0)
127 fprintf (stderr, "Could not encode\n");
128 return -1;
131 sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data);
133 gnutls_free (str_n.data);
134 gnutls_free (str_g.data);
136 fwrite (line, 1, strlen (line), fd);
140 fclose (fd);
142 return 0;
146 /* The format of a tpasswd file is:
147 * username:verifier:salt:index
149 * index is the index of the prime-generator pair in tpasswd.conf
151 static int
152 _verify_passwd_int (const char *username, const char *passwd,
153 char *verifier, char *salt,
154 const gnutls_datum_t * g, const gnutls_datum_t * n)
156 char _salt[1024];
157 gnutls_datum_t tmp, raw_salt, new_verifier;
158 size_t salt_size;
159 char *pos;
161 if (salt == NULL || verifier == NULL)
162 return -1;
164 /* copy salt, and null terminate after the ':' */
165 strcpy (_salt, salt);
166 pos = strchr (_salt, ':');
167 if (pos != NULL)
168 *pos = 0;
170 /* convert salt to binary. */
171 tmp.data = _salt;
172 tmp.size = strlen (_salt);
174 if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
176 fprintf (stderr, "Could not decode salt.\n");
177 return -1;
180 if (gnutls_srp_verifier
181 (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
183 fprintf (stderr, "Could not make the verifier\n");
184 return -1;
187 free (raw_salt.data);
189 /* encode the verifier into _salt */
190 salt_size = sizeof (_salt);
191 memset (_salt, 0, salt_size);
192 if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0)
194 fprintf (stderr, "Encoding error\n");
195 return -1;
198 free (new_verifier.data);
200 if (strncmp (verifier, _salt, strlen (_salt)) == 0)
202 fprintf (stderr, "Password verified\n");
203 return 0;
205 else
207 fprintf (stderr, "Password does NOT match\n");
209 return -1;
212 static int
213 filecopy (char *src, char *dst)
215 FILE *fd, *fd2;
216 char line[5 * 1024];
217 char *p;
219 fd = fopen (dst, "w");
220 if (fd == NULL)
222 fprintf (stderr, "Cannot open '%s' for write\n", dst);
223 return -1;
226 fd2 = fopen (src, "r");
227 if (fd2 == NULL)
229 /* empty file */
230 fclose (fd);
231 return 0;
234 line[sizeof (line) - 1] = 0;
237 p = fgets (line, sizeof (line) - 1, fd2);
238 if (p == NULL)
239 break;
241 fputs (line, fd);
243 while (1);
245 fclose (fd);
246 fclose (fd2);
248 return 0;
251 /* accepts password file */
252 static int
253 find_strchr (char *username, char *file)
255 FILE *fd;
256 char *pos;
257 char line[5 * 1024];
258 unsigned int i;
260 fd = fopen (file, "r");
261 if (fd == NULL)
263 fprintf (stderr, "Cannot open file '%s'\n", file);
264 return -1;
267 while (fgets (line, sizeof (line), fd) != NULL)
269 /* move to first ':' */
270 i = 0;
271 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
273 i++;
275 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
277 /* find the index */
278 pos = strrchr (line, ':');
279 pos++;
280 fclose (fd);
281 return atoi (pos);
285 fclose (fd);
286 return -1;
289 /* Parses the tpasswd files, in order to verify the given
290 * username/password pair.
292 static int
293 verify_passwd (char *conffile, char *tpasswd, char *username,
294 const char *passwd)
296 FILE *fd;
297 char line[5 * 1024];
298 unsigned int i;
299 gnutls_datum_t g, n;
300 int iindex;
301 char *p, *pos;
303 iindex = find_strchr (username, tpasswd);
304 if (iindex == -1)
306 fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
307 return -1;
310 fd = fopen (conffile, "r");
311 if (fd == NULL)
313 fprintf (stderr, "Cannot find %s\n", conffile);
314 return -1;
319 p = fgets (line, sizeof (line) - 1, fd);
321 while (p != NULL && atoi (p) != iindex);
323 if (p == NULL)
325 fprintf (stderr, "Cannot find entry in %s\n", conffile);
326 return -1;
328 line[sizeof (line) - 1] = 0;
330 fclose (fd);
332 if ((iindex = read_conf_values (&g, &n, line)) < 0)
334 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
335 return -1;
338 fd = fopen (tpasswd, "r");
339 if (fd == NULL)
341 fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
342 return -1;
345 while (fgets (line, sizeof (line), fd) != NULL)
347 /* move to first ':'
348 * This is the actual verifier.
350 i = 0;
351 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
353 i++;
355 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
357 char *verifier_pos, *salt_pos;
359 pos = strchr (line, ':');
360 fclose (fd);
361 if (pos == NULL)
363 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
364 return -1;
366 pos++;
367 verifier_pos = pos;
369 /* Move to the salt */
370 pos = strchr (pos, ':');
371 if (pos == NULL)
373 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
374 return -1;
376 pos++;
377 salt_pos = pos;
379 return _verify_passwd_int (username, passwd,
380 verifier_pos, salt_pos, &g, &n);
384 fclose (fd);
385 return -1;
389 #define KPASSWD "/etc/tpasswd"
390 #define KPASSWD_CONF "/etc/tpasswd.conf"
393 main (int argc, char **argv)
395 gaainfo info;
396 const char *passwd;
397 int salt_size, ret;
398 struct passwd *pwd;
400 set_program_name (argv[0]);
402 if ((ret = gnutls_global_init ()) < 0)
404 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
405 exit (1);
408 umask (066);
410 if (gaa (argc, argv, &info) != -1)
412 fprintf (stderr, "Error in the arguments.\n");
413 return -1;
416 if (info.create_conf != NULL)
418 return generate_create_conf (info.create_conf);
421 if (info.passwd == NULL)
422 info.passwd = (char *) KPASSWD;
423 if (info.passwd_conf == NULL)
424 info.passwd_conf = (char *) KPASSWD_CONF;
426 if (info.username == NULL)
428 #ifndef _WIN32
429 pwd = getpwuid (getuid ());
431 if (pwd == NULL)
433 fprintf (stderr, "No such user\n");
434 return -1;
437 info.username = pwd->pw_name;
438 #else
439 fprintf (stderr, "Please specify a user\n");
440 return -1;
441 #endif
444 salt_size = 16;
446 passwd = getpass ("Enter password: ");
447 if (passwd == NULL)
449 fprintf (stderr, "Please specify a password\n");
450 return -1;
453 /* not ready yet */
454 if (info.verify != 0)
456 return verify_passwd (info.passwd_conf, info.passwd,
457 info.username, passwd);
461 return crypt_int (info.username, passwd, salt_size,
462 info.passwd_conf, info.passwd, info.index);
466 static char *
467 _srp_crypt (const char *username, const char *passwd, int salt_size,
468 const gnutls_datum_t * g, const gnutls_datum_t * n)
470 char salt[128];
471 static char result[1024];
472 gnutls_datum_t dat_salt, txt_salt;
473 gnutls_datum_t verifier, txt_verifier;
475 if ((unsigned) salt_size > sizeof (salt))
476 return NULL;
478 /* generate the salt
480 if (_gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
482 fprintf (stderr, "Could not create nonce\n");
483 return NULL;
486 dat_salt.data = salt;
487 dat_salt.size = salt_size;
489 if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
491 fprintf (stderr, "Error getting verifier\n");
492 return NULL;
495 /* base64 encode the verifier */
496 if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
498 fprintf (stderr, "Error encoding\n");
499 free (verifier.data);
500 return NULL;
503 free (verifier.data);
505 if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
507 fprintf (stderr, "Error encoding\n");
508 return NULL;
511 sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
512 free (txt_salt.data);
513 free (txt_verifier.data);
515 return result;
521 crypt_int (const char *username, const char *passwd, int salt_size,
522 char *tpasswd_conf, char *tpasswd, int uindex)
524 FILE *fd;
525 char *cr;
526 gnutls_datum_t g, n;
527 char line[5 * 1024];
528 char *p, *pp;
529 int iindex;
530 char tmpname[1024];
532 fd = fopen (tpasswd_conf, "r");
533 if (fd == NULL)
535 fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
536 return -1;
540 { /* find the specified uindex in file */
541 p = fgets (line, sizeof (line) - 1, fd);
542 iindex = atoi (p);
544 while (p != NULL && iindex != uindex);
546 if (p == NULL)
548 fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
549 return -1;
551 line[sizeof (line) - 1] = 0;
553 fclose (fd);
554 if ((iindex = read_conf_values (&g, &n, line)) < 0)
556 fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
557 return -1;
560 cr = _srp_crypt (username, passwd, salt_size, &g, &n);
561 if (cr == NULL)
563 fprintf (stderr, "Cannot _srp_crypt()...\n");
564 return -1;
566 else
568 /* delete previous entry */
569 struct stat st;
570 FILE *fd2;
571 int put;
573 if (strlen (tpasswd) > sizeof (tmpname) + 5)
575 fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
576 return -1;
578 strcpy (tmpname, tpasswd);
579 strcat (tmpname, ".tmp");
581 if (stat (tmpname, &st) != -1)
583 fprintf (stderr, "file '%s' is locked\n", tpasswd);
584 return -1;
587 if (filecopy (tpasswd, tmpname) != 0)
589 fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
590 return -1;
593 fd = fopen (tpasswd, "w");
594 if (fd == NULL)
596 fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
597 remove (tmpname);
598 return -1;
601 fd2 = fopen (tmpname, "r");
602 if (fd2 == NULL)
604 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
605 remove (tmpname);
606 return -1;
609 put = 0;
612 p = fgets (line, sizeof (line) - 1, fd2);
613 if (p == NULL)
614 break;
616 pp = strchr (line, ':');
617 if (pp == NULL)
618 continue;
620 if (strncmp (p, username,
621 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
623 put = 1;
624 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
626 else
628 fputs (line, fd);
631 while (1);
633 if (put == 0)
635 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
638 fclose (fd);
639 fclose (fd2);
641 remove (tmpname);
646 return 0;
651 /* this function parses tpasswd.conf file. Format is:
652 * int(index):base64(n):base64(g)
654 static int
655 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
657 char *p;
658 int len;
659 int index, ret;
660 gnutls_datum_t dat;
662 index = atoi (str);
664 p = strrchr (str, ':'); /* we have g */
665 if (p == NULL)
667 return -1;
670 *p = '\0';
671 p++;
673 /* read the generator */
674 len = strlen (p);
675 if (p[len - 1] == '\n')
676 len--;
678 dat.data = p;
679 dat.size = len;
680 ret = gnutls_srp_base64_decode_alloc (&dat, g);
682 if (ret < 0)
684 fprintf (stderr, "Decoding error\n");
685 return -1;
688 /* now go for n - modulo */
689 p = strrchr (str, ':'); /* we have n */
690 if (p == NULL)
692 return -1;
695 *p = '\0';
696 p++;
698 dat.data = p;
699 dat.size = strlen (p);
701 ret = gnutls_srp_base64_decode_alloc (&dat, n);
703 if (ret < 0)
705 fprintf (stderr, "Decoding error\n");
706 free (g->data);
707 return -1;
710 return index;
713 extern void srptool_version (void);
715 void
716 srptool_version (void)
718 const char *p = PACKAGE_NAME;
719 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
720 p = PACKAGE_STRING;
721 version_etc (stdout, "srptool", p, gnutls_check_version (NULL),
722 "Nikos Mavrogiannopoulos", (char *) NULL);