Corrected initialization of key when generating request. Reported by Petr Pisar.
[gnutls.git] / src / crypt.c
blobf804f81d1a6259fa9fada63260a2539c9de36eb6
1 /*
2 * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3 * Free Software Foundation, Inc.
5 * This file is part of GnuTLS.
7 * GnuTLS is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuTLS is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see
19 * <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 if (strlen(salt) >= sizeof(_salt))
166 fprintf (stderr, "Too long salt.\n");
167 return -1;
170 /* copy salt, and null terminate after the ':' */
171 strcpy (_salt, salt);
172 pos = strchr (_salt, ':');
173 if (pos != NULL)
174 *pos = 0;
176 /* convert salt to binary. */
177 tmp.data = _salt;
178 tmp.size = strlen (_salt);
180 if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
182 fprintf (stderr, "Could not decode salt.\n");
183 return -1;
186 if (gnutls_srp_verifier
187 (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
189 fprintf (stderr, "Could not make the verifier\n");
190 return -1;
193 free (raw_salt.data);
195 /* encode the verifier into _salt */
196 salt_size = sizeof (_salt);
197 memset (_salt, 0, salt_size);
198 if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0)
200 fprintf (stderr, "Encoding error\n");
201 return -1;
204 free (new_verifier.data);
206 if (strncmp (verifier, _salt, strlen (_salt)) == 0)
208 fprintf (stderr, "Password verified\n");
209 return 0;
211 else
213 fprintf (stderr, "Password does NOT match\n");
215 return -1;
218 static int
219 filecopy (char *src, char *dst)
221 FILE *fd, *fd2;
222 char line[5 * 1024];
223 char *p;
225 fd = fopen (dst, "w");
226 if (fd == NULL)
228 fprintf (stderr, "Cannot open '%s' for write\n", dst);
229 return -1;
232 fd2 = fopen (src, "r");
233 if (fd2 == NULL)
235 /* empty file */
236 fclose (fd);
237 return 0;
240 line[sizeof (line) - 1] = 0;
243 p = fgets (line, sizeof (line) - 1, fd2);
244 if (p == NULL)
245 break;
247 fputs (line, fd);
249 while (1);
251 fclose (fd);
252 fclose (fd2);
254 return 0;
257 /* accepts password file */
258 static int
259 find_strchr (char *username, char *file)
261 FILE *fd;
262 char *pos;
263 char line[5 * 1024];
264 unsigned int i;
266 fd = fopen (file, "r");
267 if (fd == NULL)
269 fprintf (stderr, "Cannot open file '%s'\n", file);
270 return -1;
273 while (fgets (line, sizeof (line), fd) != NULL)
275 /* move to first ':' */
276 i = 0;
277 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
279 i++;
281 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
283 /* find the index */
284 pos = strrchr (line, ':');
285 pos++;
286 fclose (fd);
287 return atoi (pos);
291 fclose (fd);
292 return -1;
295 /* Parses the tpasswd files, in order to verify the given
296 * username/password pair.
298 static int
299 verify_passwd (char *conffile, char *tpasswd, char *username,
300 const char *passwd)
302 FILE *fd;
303 char line[5 * 1024];
304 unsigned int i;
305 gnutls_datum_t g, n;
306 int iindex;
307 char *p, *pos;
309 iindex = find_strchr (username, tpasswd);
310 if (iindex == -1)
312 fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
313 return -1;
316 fd = fopen (conffile, "r");
317 if (fd == NULL)
319 fprintf (stderr, "Cannot find %s\n", conffile);
320 return -1;
325 p = fgets (line, sizeof (line) - 1, fd);
327 while (p != NULL && atoi (p) != iindex);
329 if (p == NULL)
331 fprintf (stderr, "Cannot find entry in %s\n", conffile);
332 return -1;
334 line[sizeof (line) - 1] = 0;
336 fclose (fd);
338 if ((iindex = read_conf_values (&g, &n, line)) < 0)
340 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
341 return -1;
344 fd = fopen (tpasswd, "r");
345 if (fd == NULL)
347 fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
348 return -1;
351 while (fgets (line, sizeof (line), fd) != NULL)
353 /* move to first ':'
354 * This is the actual verifier.
356 i = 0;
357 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
359 i++;
361 if (strncmp (username, line, MAX (i, strlen (username))) == 0)
363 char *verifier_pos, *salt_pos;
365 pos = strchr (line, ':');
366 fclose (fd);
367 if (pos == NULL)
369 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
370 return -1;
372 pos++;
373 verifier_pos = pos;
375 /* Move to the salt */
376 pos = strchr (pos, ':');
377 if (pos == NULL)
379 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
380 return -1;
382 pos++;
383 salt_pos = pos;
385 return _verify_passwd_int (username, passwd,
386 verifier_pos, salt_pos, &g, &n);
390 fclose (fd);
391 return -1;
395 #define KPASSWD "/etc/tpasswd"
396 #define KPASSWD_CONF "/etc/tpasswd.conf"
398 static void
399 tls_log_func (int level, const char *str)
401 fprintf (stderr, "|<%d>| %s", level, str);
404 int main (int argc, char **argv)
406 gaainfo info;
407 const char *passwd;
408 int salt_size, ret;
409 #ifndef _WIN32
410 struct passwd *pwd;
411 #endif
413 set_program_name (argv[0]);
415 if ((ret = gnutls_global_init ()) < 0)
417 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
418 exit (1);
421 umask (066);
423 if (gaa (argc, argv, &info) != -1)
425 fprintf (stderr, "Error in the arguments.\n");
426 return -1;
429 gnutls_global_set_log_function (tls_log_func);
430 gnutls_global_set_log_level (info.debug);
432 if (info.create_conf != NULL)
434 return generate_create_conf (info.create_conf);
437 if (info.passwd == NULL)
438 info.passwd = (char *) KPASSWD;
439 if (info.passwd_conf == NULL)
440 info.passwd_conf = (char *) KPASSWD_CONF;
442 if (info.username == NULL)
444 #ifndef _WIN32
445 pwd = getpwuid (getuid ());
447 if (pwd == NULL)
449 fprintf (stderr, "No such user\n");
450 return -1;
453 info.username = pwd->pw_name;
454 #else
455 fprintf (stderr, "Please specify a user\n");
456 return -1;
457 #endif
460 salt_size = 16;
462 passwd = getpass ("Enter password: ");
463 if (passwd == NULL)
465 fprintf (stderr, "Please specify a password\n");
466 return -1;
469 /* not ready yet */
470 if (info.verify != 0)
472 return verify_passwd (info.passwd_conf, info.passwd,
473 info.username, passwd);
477 return crypt_int (info.username, passwd, salt_size,
478 info.passwd_conf, info.passwd, info.index);
482 static char *
483 _srp_crypt (const char *username, const char *passwd, int salt_size,
484 const gnutls_datum_t * g, const gnutls_datum_t * n)
486 char salt[128];
487 static char result[1024];
488 gnutls_datum_t dat_salt, txt_salt;
489 gnutls_datum_t verifier, txt_verifier;
491 if ((unsigned) salt_size > sizeof (salt))
492 return NULL;
494 /* generate the salt
496 if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
498 fprintf (stderr, "Could not create nonce\n");
499 return NULL;
502 dat_salt.data = salt;
503 dat_salt.size = salt_size;
505 if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
507 fprintf (stderr, "Error getting verifier\n");
508 return NULL;
511 /* base64 encode the verifier */
512 if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
514 fprintf (stderr, "Error encoding\n");
515 free (verifier.data);
516 return NULL;
519 free (verifier.data);
521 if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
523 fprintf (stderr, "Error encoding\n");
524 return NULL;
527 sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
528 free (txt_salt.data);
529 free (txt_verifier.data);
531 return result;
537 crypt_int (const char *username, const char *passwd, int salt_size,
538 char *tpasswd_conf, char *tpasswd, int uindex)
540 FILE *fd;
541 char *cr;
542 gnutls_datum_t g, n;
543 char line[5 * 1024];
544 char *p, *pp;
545 int iindex;
546 char tmpname[1024];
548 fd = fopen (tpasswd_conf, "r");
549 if (fd == NULL)
551 fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
552 return -1;
556 { /* find the specified uindex in file */
557 p = fgets (line, sizeof (line) - 1, fd);
558 iindex = atoi (p);
560 while (p != NULL && iindex != uindex);
562 if (p == NULL)
564 fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
565 return -1;
567 line[sizeof (line) - 1] = 0;
569 fclose (fd);
570 if ((iindex = read_conf_values (&g, &n, line)) < 0)
572 fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
573 return -1;
576 cr = _srp_crypt (username, passwd, salt_size, &g, &n);
577 if (cr == NULL)
579 fprintf (stderr, "Cannot _srp_crypt()...\n");
580 return -1;
582 else
584 /* delete previous entry */
585 struct stat st;
586 FILE *fd2;
587 int put;
589 if (strlen (tpasswd) > sizeof (tmpname) + 5)
591 fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
592 return -1;
594 strcpy (tmpname, tpasswd);
595 strcat (tmpname, ".tmp");
597 if (stat (tmpname, &st) != -1)
599 fprintf (stderr, "file '%s' is locked\n", tpasswd);
600 return -1;
603 if (filecopy (tpasswd, tmpname) != 0)
605 fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
606 return -1;
609 fd = fopen (tpasswd, "w");
610 if (fd == NULL)
612 fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
613 remove (tmpname);
614 return -1;
617 fd2 = fopen (tmpname, "r");
618 if (fd2 == NULL)
620 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
621 remove (tmpname);
622 return -1;
625 put = 0;
628 p = fgets (line, sizeof (line) - 1, fd2);
629 if (p == NULL)
630 break;
632 pp = strchr (line, ':');
633 if (pp == NULL)
634 continue;
636 if (strncmp (p, username,
637 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
639 put = 1;
640 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
642 else
644 fputs (line, fd);
647 while (1);
649 if (put == 0)
651 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
654 fclose (fd);
655 fclose (fd2);
657 remove (tmpname);
662 return 0;
667 /* this function parses tpasswd.conf file. Format is:
668 * int(index):base64(n):base64(g)
670 static int
671 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
673 char *p;
674 int len;
675 int index, ret;
676 gnutls_datum_t dat;
678 index = atoi (str);
680 p = strrchr (str, ':'); /* we have g */
681 if (p == NULL)
683 return -1;
686 *p = '\0';
687 p++;
689 /* read the generator */
690 len = strlen (p);
691 if (p[len - 1] == '\n')
692 len--;
694 dat.data = p;
695 dat.size = len;
696 ret = gnutls_srp_base64_decode_alloc (&dat, g);
698 if (ret < 0)
700 fprintf (stderr, "Decoding error\n");
701 return -1;
704 /* now go for n - modulo */
705 p = strrchr (str, ':'); /* we have n */
706 if (p == NULL)
708 return -1;
711 *p = '\0';
712 p++;
714 dat.data = p;
715 dat.size = strlen (p);
717 ret = gnutls_srp_base64_decode_alloc (&dat, n);
719 if (ret < 0)
721 fprintf (stderr, "Decoding error\n");
722 free (g->data);
723 return -1;
726 return index;
729 extern void srptool_version (void);
731 void
732 srptool_version (void)
734 const char *p = PACKAGE_NAME;
735 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
736 p = PACKAGE_STRING;
737 version_etc (stdout, "srptool", p, gnutls_check_version (NULL),
738 "Nikos Mavrogiannopoulos", (char *) NULL);