Update `NEWS'.
[gnutls.git] / src / crypt.c
blobe45b90ca9aa96e6710f473c0931535b57dac937c
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007 Simon Josefsson
3 * Copyright (C) 2001,2003 Nikos Mavroyanopoulos
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 2 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, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <config.h>
27 #ifndef ENABLE_SRP
29 #include <stdio.h>
31 int
32 main (int argc, char **argv)
34 printf ("\nSRP not supported. This program is a dummy.\n\n");
35 return 1;
38 void
39 srptool_version (void)
41 fprintf (stderr, "GNU TLS dummy srptool.\n");
44 #else
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <gnutls/gnutls.h>
50 #include <gnutls/extra.h>
51 #include <crypt-gaa.h>
53 #include <gc.h> /* for randomize */
55 #include <sys/types.h>
56 #include <sys/stat.h>
58 #ifndef _WIN32
59 # include <pwd.h>
60 # include <unistd.h>
61 #else
62 # include <windows.h>
63 #endif
65 /* Gnulib portability files. */
66 #include <getpass.h>
68 #define _MAX(x,y) (x>y?x:y)
70 /* This may need some rewrite. A lot of stuff which should be here
71 * are in the library, which is not good.
74 int crypt_int (const char *username, const char *passwd, int salt,
75 char *tpasswd_conf, char *tpasswd, int uindex);
76 static int read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str);
77 static int _verify_passwd_int (const char *username, const char *passwd,
78 char *verifier, char *salt,
79 const gnutls_datum_t * g,
80 const gnutls_datum_t * n);
82 void
83 srptool_version (void)
85 const char *v = gnutls_check_version (NULL);
87 printf ("srptool (GnuTLS) %s\n", LIBGNUTLS_VERSION);
88 if (strcmp (v, LIBGNUTLS_VERSION) != 0)
89 printf ("libgnutls %s\n", v);
93 static void
94 print_num (const char *msg, const gnutls_datum_t * num)
96 unsigned int i;
98 printf ("%s:\t", msg);
100 for (i = 0; i < num->size; i++)
102 if (i != 0 && i % 12 == 0)
103 printf ("\n\t");
104 else if (i != 0 && i != num->size)
105 printf (":");
106 printf ("%.2x", num->data[i]);
108 printf ("\n\n");
113 generate_create_conf (char *tpasswd_conf)
115 FILE *fd;
116 char line[5 * 1024];
117 int index = 1;
118 gnutls_datum_t g, n;
119 gnutls_datum_t str_g, str_n;
121 fd = fopen (tpasswd_conf, "w");
122 if (fd == NULL)
124 fprintf (stderr, "Cannot open file '%s'\n", tpasswd_conf);
125 return -1;
128 for (index = 1; index <= 3; index++)
131 if (index == 1)
133 n = gnutls_srp_1024_group_prime;
134 g = gnutls_srp_1024_group_generator;
136 else if (index == 2)
138 n = gnutls_srp_1536_group_prime;
139 g = gnutls_srp_1536_group_generator;
141 else
143 n = gnutls_srp_2048_group_prime;
144 g = gnutls_srp_2048_group_generator;
147 printf ("\nGroup %d, of %d bits:\n", index, n.size * 8);
148 print_num ("Generator", &g);
149 print_num ("Prime", &n);
151 if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0)
153 fprintf (stderr, "Could not encode\n");
154 return -1;
157 if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0)
159 fprintf (stderr, "Could not encode\n");
160 return -1;
163 sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data);
165 gnutls_free (str_n.data);
166 gnutls_free (str_g.data);
168 fwrite (line, 1, strlen (line), fd);
172 fclose (fd);
174 return 0;
178 /* The format of a tpasswd file is:
179 * username:verifier:salt:index
181 * index is the index of the prime-generator pair in tpasswd.conf
183 static int
184 _verify_passwd_int (const char *username, const char *passwd,
185 char *verifier, char *salt,
186 const gnutls_datum_t * g, const gnutls_datum_t * n)
188 char _salt[1024];
189 gnutls_datum_t tmp, raw_salt, new_verifier;
190 size_t salt_size;
191 char *pos;
193 if (salt == NULL || verifier == NULL)
194 return -1;
196 /* copy salt, and null terminate after the ':' */
197 strcpy (_salt, salt);
198 pos = strchr (_salt, ':');
199 if (pos != NULL)
200 *pos = 0;
202 /* convert salt to binary. */
203 tmp.data = _salt;
204 tmp.size = strlen (_salt);
206 if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
208 fprintf (stderr, "Could not decode salt.\n");
209 return -1;
212 if (gnutls_srp_verifier
213 (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
215 fprintf (stderr, "Could not make the verifier\n");
216 return -1;
219 free (raw_salt.data);
221 /* encode the verifier into _salt */
222 salt_size = sizeof (_salt);
223 if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0)
225 fprintf (stderr, "Encoding error\n");
226 return -1;
229 free (new_verifier.data);
231 if (strncmp (verifier, _salt, strlen (_salt)) == 0)
233 fprintf (stderr, "Password verified\n");
234 return 0;
236 else
238 fprintf (stderr, "Password does NOT match\n");
240 return -1;
243 static int
244 filecopy (char *src, char *dst)
246 FILE *fd, *fd2;
247 char line[5 * 1024];
248 char *p;
250 fd = fopen (dst, "w");
251 if (fd == NULL)
253 fprintf (stderr, "Cannot open '%s' for write\n", dst);
254 return -1;
257 fd2 = fopen (src, "r");
258 if (fd2 == NULL)
260 /* empty file */
261 fclose (fd);
262 return 0;
265 line[sizeof (line) - 1] = 0;
268 p = fgets (line, sizeof (line) - 1, fd2);
269 if (p == NULL)
270 break;
272 fputs (line, fd);
274 while (1);
276 fclose (fd);
277 fclose (fd2);
279 return 0;
282 /* accepts password file */
283 static int
284 find_strchr (char *username, char *file)
286 FILE *fd;
287 char *pos;
288 char line[5 * 1024];
289 unsigned int i;
291 fd = fopen (file, "r");
292 if (fd == NULL)
294 fprintf (stderr, "Cannot open file '%s'\n", file);
295 return -1;
298 while (fgets (line, sizeof (line), fd) != NULL)
300 /* move to first ':' */
301 i = 0;
302 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
304 i++;
306 if (strncmp (username, line, _MAX (i, strlen (username))) == 0)
308 /* find the index */
309 pos = strrchr (line, ':');
310 pos++;
311 fclose (fd);
312 return atoi (pos);
316 fclose (fd);
317 return -1;
320 /* Parses the tpasswd files, in order to verify the given
321 * username/password pair.
324 verify_passwd (char *conffile, char *tpasswd, char *username,
325 const char *passwd)
327 FILE *fd;
328 char line[5 * 1024];
329 unsigned int i;
330 gnutls_datum_t g, n;
331 int iindex;
332 char *p, *pos;
334 iindex = find_strchr (username, tpasswd);
335 if (iindex == -1)
337 fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
338 return -1;
341 fd = fopen (conffile, "r");
342 if (fd == NULL)
344 fprintf (stderr, "Cannot find %s\n", conffile);
345 return -1;
350 p = fgets (line, sizeof (line) - 1, fd);
352 while (p != NULL && atoi (p) != iindex);
354 if (p == NULL)
356 fprintf (stderr, "Cannot find entry in %s\n", conffile);
357 return -1;
359 line[sizeof (line) - 1] = 0;
361 fclose (fd);
363 if ((iindex = read_conf_values (&g, &n, line)) < 0)
365 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
366 return -1;
369 fd = fopen (tpasswd, "r");
370 if (fd == NULL)
372 fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
373 return -1;
376 while (fgets (line, sizeof (line), fd) != NULL)
378 /* move to first ':'
379 * This is the actual verifier.
381 i = 0;
382 while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
384 i++;
386 if (strncmp (username, line, _MAX (i, strlen (username))) == 0)
388 char *verifier_pos, *salt_pos;
390 pos = strchr (line, ':');
391 fclose (fd);
392 if (pos == NULL)
394 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
395 return -1;
397 pos++;
398 verifier_pos = pos;
400 /* Move to the salt */
401 pos = strchr (pos, ':');
402 if (pos == NULL)
404 fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
405 return -1;
407 pos++;
408 salt_pos = pos;
410 return _verify_passwd_int (username, passwd,
411 verifier_pos, salt_pos, &g, &n);
415 fclose (fd);
416 return -1;
420 #define KPASSWD "/etc/tpasswd"
421 #define KPASSWD_CONF "/etc/tpasswd.conf"
424 main (int argc, char **argv)
426 gaainfo info;
427 const char *passwd;
428 int salt, ret;
429 struct passwd *pwd;
431 if ((ret = gnutls_global_init ()) < 0)
433 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
434 exit (1);
437 #ifdef HAVE_UMASK
438 umask (066);
439 #endif
441 if (gaa (argc, argv, &info) != -1)
443 fprintf (stderr, "Error in the arguments.\n");
444 return -1;
447 salt = info.salt;
449 if (info.create_conf != NULL)
451 return generate_create_conf (info.create_conf);
454 if (info.passwd == NULL)
455 info.passwd = KPASSWD;
456 if (info.passwd_conf == NULL)
457 info.passwd_conf = KPASSWD_CONF;
459 if (info.username == NULL)
461 #ifndef _WIN32
462 pwd = getpwuid (getuid ());
464 if (pwd == NULL)
466 fprintf (stderr, "No such user\n");
467 return -1;
470 info.username = pwd->pw_name;
471 #else
472 fprintf (stderr, "Please specify a user\n");
473 return -1;
474 #endif
477 salt = 16;
479 passwd = getpass ("Enter password: ");
480 if (passwd == NULL)
482 fprintf (stderr, "Please specify a password\n");
483 return -1;
486 /* not ready yet */
487 if (info.verify != 0)
489 return verify_passwd (info.passwd_conf, info.passwd,
490 info.username, passwd);
494 return crypt_int (info.username, passwd, salt,
495 info.passwd_conf, info.passwd, info.index);
499 char *
500 _srp_crypt (const char *username, const char *passwd, int salt_size,
501 const gnutls_datum_t * g, const gnutls_datum_t * n)
503 char salt[128];
504 static char result[1024];
505 gnutls_datum_t dat_salt, txt_salt;
506 gnutls_datum_t verifier, txt_verifier;
508 if ((unsigned) salt_size > sizeof (salt))
509 return NULL;
511 /* generate the salt
513 if (gc_nonce (salt, salt_size) != GC_OK)
515 fprintf (stderr, "Could not create nonce\n");
516 return NULL;
519 dat_salt.data = salt;
520 dat_salt.size = salt_size;
522 if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
524 fprintf (stderr, "Error getting verifier\n");
525 return NULL;
528 /* base64 encode the verifier */
529 if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
531 fprintf (stderr, "Error encoding\n");
532 free (verifier.data);
533 return NULL;
536 free (verifier.data);
538 if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
540 fprintf (stderr, "Error encoding\n");
541 return NULL;
544 sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
545 free (txt_salt.data);
546 free (txt_verifier.data);
548 return result;
554 crypt_int (const char *username, const char *passwd, int salt_size,
555 char *tpasswd_conf, char *tpasswd, int uindex)
557 FILE *fd;
558 char *cr;
559 gnutls_datum_t g, n;
560 char line[5 * 1024];
561 char *p, *pp;
562 int iindex;
563 char tmpname[1024];
565 fd = fopen (tpasswd_conf, "r");
566 if (fd == NULL)
568 fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
569 return -1;
573 { /* find the specified uindex in file */
574 p = fgets (line, sizeof (line) - 1, fd);
575 iindex = atoi (p);
577 while (p != NULL && iindex != uindex);
579 if (p == NULL)
581 fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
582 return -1;
584 line[sizeof (line) - 1] = 0;
586 fclose (fd);
587 if ((iindex = read_conf_values (&g, &n, line)) < 0)
589 fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
590 return -1;
593 cr = _srp_crypt (username, passwd, salt_size, &g, &n);
594 if (cr == NULL)
596 fprintf (stderr, "Cannot _srp_crypt()...\n");
597 return -1;
599 else
601 /* delete previous entry */
602 struct stat st;
603 FILE *fd2;
604 int put;
606 if (strlen (tpasswd) > sizeof (tmpname) + 5)
608 fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
609 return -1;
611 strcpy (tmpname, tpasswd);
612 strcat (tmpname, ".tmp");
614 if (stat (tmpname, &st) != -1)
616 fprintf (stderr, "file '%s' is locked\n", tpasswd);
617 return -1;
620 if (filecopy (tpasswd, tmpname) != 0)
622 fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
623 return -1;
626 fd = fopen (tpasswd, "w");
627 if (fd == NULL)
629 fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
630 remove (tmpname);
631 return -1;
634 fd2 = fopen (tmpname, "r");
635 if (fd2 == NULL)
637 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
638 remove (tmpname);
639 return -1;
642 put = 0;
645 p = fgets (line, sizeof (line) - 1, fd2);
646 if (p == NULL)
647 break;
649 pp = strchr (line, ':');
650 if (pp == NULL)
651 continue;
653 if (strncmp
654 (p, username,
655 _MAX (strlen (username), (unsigned int) (pp - p))) == 0)
657 put = 1;
658 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
660 else
662 fputs (line, fd);
665 while (1);
667 if (put == 0)
669 fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
672 fclose (fd);
673 fclose (fd2);
675 remove (tmpname);
680 return 0;
685 /* this function parses tpasswd.conf file. Format is:
686 * int(index):base64(n):base64(g)
688 static int
689 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
691 char *p;
692 int len;
693 int index, ret;
694 gnutls_datum_t dat;
696 index = atoi (str);
698 p = strrchr (str, ':'); /* we have g */
699 if (p == NULL)
701 return -1;
704 *p = '\0';
705 p++;
707 /* read the generator */
708 len = strlen (p);
709 if (p[len - 1] == '\n')
710 len--;
712 dat.data = p;
713 dat.size = len;
714 ret = gnutls_srp_base64_decode_alloc (&dat, g);
716 if (ret < 0)
718 fprintf (stderr, "Decoding error\n");
719 return -1;
722 /* now go for n - modulo */
723 p = strrchr (str, ':'); /* we have n */
724 if (p == NULL)
726 return -1;
729 *p = '\0';
730 p++;
732 dat.data = p;
733 dat.size = strlen (p);
735 ret = gnutls_srp_base64_decode_alloc (&dat, n);
737 if (ret < 0)
739 fprintf (stderr, "Decoding error\n");
740 free (g->data);
741 return -1;
744 return index;
747 #endif /* ENABLE_SRP */