Tizen 2.0 Release
[external/libgnutls26.git] / src / crypt.c
1 /*
2  * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3  * Free Software Foundation, Inc.
4  *
5  * This file is part of GnuTLS.
6  *
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.
11  *
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.
16  *
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/>.
20  */
21
22 #include <config.h>
23
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 */
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34
35 #ifndef _WIN32
36 #include <pwd.h>
37 #include <unistd.h>
38 #else
39 #include <windows.h>
40 #endif
41
42 /* Gnulib portability files. */
43 #include <getpass.h>
44 #include <minmax.h>
45 #include <progname.h>
46 #include <version-etc.h>
47
48 /* This may need some rewrite. A lot of stuff which should be here
49  * are in the library, which is not good.
50  */
51
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);
60
61 static void
62 print_num (const char *msg, const gnutls_datum_t * num)
63 {
64   unsigned int i;
65
66   printf ("%s:\t", msg);
67
68   for (i = 0; i < num->size; i++)
69     {
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]);
75     }
76   printf ("\n\n");
77
78 }
79
80 static int
81 generate_create_conf (char *tpasswd_conf)
82 {
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;
88
89   fd = fopen (tpasswd_conf, "w");
90   if (fd == NULL)
91     {
92       fprintf (stderr, "Cannot open file '%s'\n", tpasswd_conf);
93       return -1;
94     }
95
96   for (index = 1; index <= 3; index++)
97     {
98
99       if (index == 1)
100         {
101           n = gnutls_srp_1024_group_prime;
102           g = gnutls_srp_1024_group_generator;
103         }
104       else if (index == 2)
105         {
106           n = gnutls_srp_1536_group_prime;
107           g = gnutls_srp_1536_group_generator;
108         }
109       else
110         {
111           n = gnutls_srp_2048_group_prime;
112           g = gnutls_srp_2048_group_generator;
113         }
114
115       printf ("\nGroup %d, of %d bits:\n", index, n.size * 8);
116       print_num ("Generator", &g);
117       print_num ("Prime", &n);
118
119       if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0)
120         {
121           fprintf (stderr, "Could not encode\n");
122           return -1;
123         }
124
125       if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0)
126         {
127           fprintf (stderr, "Could not encode\n");
128           return -1;
129         }
130
131       sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data);
132
133       gnutls_free (str_n.data);
134       gnutls_free (str_g.data);
135
136       fwrite (line, 1, strlen (line), fd);
137
138     }
139
140   fclose (fd);
141
142   return 0;
143
144 }
145
146 /* The format of a tpasswd file is:
147  * username:verifier:salt:index
148  *
149  * index is the index of the prime-generator pair in tpasswd.conf
150  */
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)
155 {
156   char _salt[1024];
157   gnutls_datum_t tmp, raw_salt, new_verifier;
158   size_t salt_size;
159   char *pos;
160
161   if (salt == NULL || verifier == NULL)
162     return -1;
163
164   if (strlen(salt) >= sizeof(_salt))
165     {
166       fprintf (stderr, "Too long salt.\n");
167       return -1;
168     }
169
170   /* copy salt, and null terminate after the ':' */
171   strcpy (_salt, salt);
172   pos = strchr (_salt, ':');
173   if (pos != NULL)
174     *pos = 0;
175
176   /* convert salt to binary. */
177   tmp.data = _salt;
178   tmp.size = strlen (_salt);
179
180   if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0)
181     {
182       fprintf (stderr, "Could not decode salt.\n");
183       return -1;
184     }
185
186   if (gnutls_srp_verifier
187       (username, passwd, &raw_salt, g, n, &new_verifier) < 0)
188     {
189       fprintf (stderr, "Could not make the verifier\n");
190       return -1;
191     }
192
193   free (raw_salt.data);
194
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)
199     {
200       fprintf (stderr, "Encoding error\n");
201       return -1;
202     }
203
204   free (new_verifier.data);
205
206   if (strncmp (verifier, _salt, strlen (_salt)) == 0)
207     {
208       fprintf (stderr, "Password verified\n");
209       return 0;
210     }
211   else
212     {
213       fprintf (stderr, "Password does NOT match\n");
214     }
215   return -1;
216 }
217
218 static int
219 filecopy (char *src, char *dst)
220 {
221   FILE *fd, *fd2;
222   char line[5 * 1024];
223   char *p;
224
225   fd = fopen (dst, "w");
226   if (fd == NULL)
227     {
228       fprintf (stderr, "Cannot open '%s' for write\n", dst);
229       return -1;
230     }
231
232   fd2 = fopen (src, "r");
233   if (fd2 == NULL)
234     {
235       /* empty file */
236       fclose (fd);
237       return 0;
238     }
239
240   line[sizeof (line) - 1] = 0;
241   do
242     {
243       p = fgets (line, sizeof (line) - 1, fd2);
244       if (p == NULL)
245         break;
246
247       fputs (line, fd);
248     }
249   while (1);
250
251   fclose (fd);
252   fclose (fd2);
253
254   return 0;
255 }
256
257 /* accepts password file */
258 static int
259 find_strchr (char *username, char *file)
260 {
261   FILE *fd;
262   char *pos;
263   char line[5 * 1024];
264   unsigned int i;
265
266   fd = fopen (file, "r");
267   if (fd == NULL)
268     {
269       fprintf (stderr, "Cannot open file '%s'\n", file);
270       return -1;
271     }
272
273   while (fgets (line, sizeof (line), fd) != NULL)
274     {
275       /* move to first ':' */
276       i = 0;
277       while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
278         {
279           i++;
280         }
281       if (strncmp (username, line, MAX (i, strlen (username))) == 0)
282         {
283           /* find the index */
284           pos = strrchr (line, ':');
285           pos++;
286           fclose (fd);
287           return atoi (pos);
288         }
289     }
290
291   fclose (fd);
292   return -1;
293 }
294
295 /* Parses the tpasswd files, in order to verify the given
296  * username/password pair.
297  */
298 static int
299 verify_passwd (char *conffile, char *tpasswd, char *username,
300                const char *passwd)
301 {
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;
308
309   iindex = find_strchr (username, tpasswd);
310   if (iindex == -1)
311     {
312       fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd);
313       return -1;
314     }
315
316   fd = fopen (conffile, "r");
317   if (fd == NULL)
318     {
319       fprintf (stderr, "Cannot find %s\n", conffile);
320       return -1;
321     }
322
323   do
324     {
325       p = fgets (line, sizeof (line) - 1, fd);
326     }
327   while (p != NULL && atoi (p) != iindex);
328
329   if (p == NULL)
330     {
331       fprintf (stderr, "Cannot find entry in %s\n", conffile);
332       return -1;
333     }
334   line[sizeof (line) - 1] = 0;
335
336   fclose (fd);
337
338   if ((iindex = read_conf_values (&g, &n, line)) < 0)
339     {
340       fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
341       return -1;
342     }
343
344   fd = fopen (tpasswd, "r");
345   if (fd == NULL)
346     {
347       fprintf (stderr, "Cannot open file '%s'\n", tpasswd);
348       return -1;
349     }
350
351   while (fgets (line, sizeof (line), fd) != NULL)
352     {
353       /* move to first ':' 
354        * This is the actual verifier.
355        */
356       i = 0;
357       while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line)))
358         {
359           i++;
360         }
361       if (strncmp (username, line, MAX (i, strlen (username))) == 0)
362         {
363           char *verifier_pos, *salt_pos;
364
365           pos = strchr (line, ':');
366           fclose (fd);
367           if (pos == NULL)
368             {
369               fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
370               return -1;
371             }
372           pos++;
373           verifier_pos = pos;
374
375           /* Move to the salt */
376           pos = strchr (pos, ':');
377           if (pos == NULL)
378             {
379               fprintf (stderr, "Cannot parse conf file '%s'\n", conffile);
380               return -1;
381             }
382           pos++;
383           salt_pos = pos;
384
385           return _verify_passwd_int (username, passwd,
386                                      verifier_pos, salt_pos, &g, &n);
387         }
388     }
389
390   fclose (fd);
391   return -1;
392
393 }
394
395 #define KPASSWD "/etc/tpasswd"
396 #define KPASSWD_CONF "/etc/tpasswd.conf"
397
398 static void
399 tls_log_func (int level, const char *str)
400 {
401   fprintf (stderr, "|<%d>| %s", level, str);
402 }
403
404 int main (int argc, char **argv)
405 {
406   gaainfo info;
407   const char *passwd;
408   int salt_size, ret;
409 #ifndef _WIN32
410    struct passwd *pwd;
411 #endif
412
413   set_program_name (argv[0]);
414
415   if ((ret = gnutls_global_init ()) < 0)
416     {
417       fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
418       exit (1);
419     }
420
421   umask (066);
422
423   if (gaa (argc, argv, &info) != -1)
424     {
425       fprintf (stderr, "Error in the arguments.\n");
426       return -1;
427     }
428
429   gnutls_global_set_log_function (tls_log_func);
430   gnutls_global_set_log_level (info.debug);
431
432   if (info.create_conf != NULL)
433     {
434       return generate_create_conf (info.create_conf);
435     }
436
437   if (info.passwd == NULL)
438     info.passwd = (char *) KPASSWD;
439   if (info.passwd_conf == NULL)
440     info.passwd_conf = (char *) KPASSWD_CONF;
441
442   if (info.username == NULL)
443     {
444 #ifndef _WIN32
445       pwd = getpwuid (getuid ());
446
447       if (pwd == NULL)
448         {
449           fprintf (stderr, "No such user\n");
450           return -1;
451         }
452
453       info.username = pwd->pw_name;
454 #else
455       fprintf (stderr, "Please specify a user\n");
456       return -1;
457 #endif
458     }
459
460   salt_size = 16;
461
462   passwd = getpass ("Enter password: ");
463   if (passwd == NULL)
464     {
465       fprintf (stderr, "Please specify a password\n");
466       return -1;
467     }
468
469 /* not ready yet */
470   if (info.verify != 0)
471     {
472       return verify_passwd (info.passwd_conf, info.passwd,
473                             info.username, passwd);
474     }
475
476
477   return crypt_int (info.username, passwd, salt_size,
478                     info.passwd_conf, info.passwd, info.index);
479
480 }
481
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)
485 {
486   char salt[128];
487   static char result[1024];
488   gnutls_datum_t dat_salt, txt_salt;
489   gnutls_datum_t verifier, txt_verifier;
490
491   if ((unsigned) salt_size > sizeof (salt))
492     return NULL;
493
494   /* generate the salt
495    */
496   if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
497     {
498       fprintf (stderr, "Could not create nonce\n");
499       return NULL;
500     }
501
502   dat_salt.data = salt;
503   dat_salt.size = salt_size;
504
505   if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0)
506     {
507       fprintf (stderr, "Error getting verifier\n");
508       return NULL;
509     }
510
511   /* base64 encode the verifier */
512   if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0)
513     {
514       fprintf (stderr, "Error encoding\n");
515       free (verifier.data);
516       return NULL;
517     }
518
519   free (verifier.data);
520
521   if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0)
522     {
523       fprintf (stderr, "Error encoding\n");
524       return NULL;
525     }
526
527   sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data);
528   free (txt_salt.data);
529   free (txt_verifier.data);
530
531   return result;
532
533 }
534
535
536 int
537 crypt_int (const char *username, const char *passwd, int salt_size,
538            char *tpasswd_conf, char *tpasswd, int uindex)
539 {
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];
547
548   fd = fopen (tpasswd_conf, "r");
549   if (fd == NULL)
550     {
551       fprintf (stderr, "Cannot find %s\n", tpasswd_conf);
552       return -1;
553     }
554
555   do
556     {                           /* find the specified uindex in file */
557       p = fgets (line, sizeof (line) - 1, fd);
558       iindex = atoi (p);
559     }
560   while (p != NULL && iindex != uindex);
561
562   if (p == NULL)
563     {
564       fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf);
565       return -1;
566     }
567   line[sizeof (line) - 1] = 0;
568
569   fclose (fd);
570   if ((iindex = read_conf_values (&g, &n, line)) < 0)
571     {
572       fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf);
573       return -1;
574     }
575
576   cr = _srp_crypt (username, passwd, salt_size, &g, &n);
577   if (cr == NULL)
578     {
579       fprintf (stderr, "Cannot _srp_crypt()...\n");
580       return -1;
581     }
582   else
583     {
584       /* delete previous entry */
585       struct stat st;
586       FILE *fd2;
587       int put;
588
589       if (strlen (tpasswd) > sizeof (tmpname) + 5)
590         {
591           fprintf (stderr, "file '%s' is tooooo long\n", tpasswd);
592           return -1;
593         }
594       strcpy (tmpname, tpasswd);
595       strcat (tmpname, ".tmp");
596
597       if (stat (tmpname, &st) != -1)
598         {
599           fprintf (stderr, "file '%s' is locked\n", tpasswd);
600           return -1;
601         }
602
603       if (filecopy (tpasswd, tmpname) != 0)
604         {
605           fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname);
606           return -1;
607         }
608
609       fd = fopen (tpasswd, "w");
610       if (fd == NULL)
611         {
612           fprintf (stderr, "Cannot open '%s' for write\n", tpasswd);
613           remove (tmpname);
614           return -1;
615         }
616
617       fd2 = fopen (tmpname, "r");
618       if (fd2 == NULL)
619         {
620           fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
621           remove (tmpname);
622           return -1;
623         }
624
625       put = 0;
626       do
627         {
628           p = fgets (line, sizeof (line) - 1, fd2);
629           if (p == NULL)
630             break;
631
632           pp = strchr (line, ':');
633           if (pp == NULL)
634             continue;
635
636           if (strncmp (p, username,
637                        MAX (strlen (username), (unsigned int) (pp - p))) == 0)
638             {
639               put = 1;
640               fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
641             }
642           else
643             {
644               fputs (line, fd);
645             }
646         }
647       while (1);
648
649       if (put == 0)
650         {
651           fprintf (fd, "%s:%s:%u\n", username, cr, iindex);
652         }
653
654       fclose (fd);
655       fclose (fd2);
656
657       remove (tmpname);
658
659     }
660
661
662   return 0;
663 }
664
665
666
667 /* this function parses tpasswd.conf file. Format is:
668  * int(index):base64(n):base64(g)
669  */
670 static int
671 read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str)
672 {
673   char *p;
674   int len;
675   int index, ret;
676   gnutls_datum_t dat;
677
678   index = atoi (str);
679
680   p = strrchr (str, ':');       /* we have g */
681   if (p == NULL)
682     {
683       return -1;
684     }
685
686   *p = '\0';
687   p++;
688
689   /* read the generator */
690   len = strlen (p);
691   if (p[len - 1] == '\n')
692     len--;
693
694   dat.data = p;
695   dat.size = len;
696   ret = gnutls_srp_base64_decode_alloc (&dat, g);
697
698   if (ret < 0)
699     {
700       fprintf (stderr, "Decoding error\n");
701       return -1;
702     }
703
704   /* now go for n - modulo */
705   p = strrchr (str, ':');       /* we have n */
706   if (p == NULL)
707     {
708       return -1;
709     }
710
711   *p = '\0';
712   p++;
713
714   dat.data = p;
715   dat.size = strlen (p);
716
717   ret = gnutls_srp_base64_decode_alloc (&dat, n);
718
719   if (ret < 0)
720     {
721       fprintf (stderr, "Decoding error\n");
722       free (g->data);
723       return -1;
724     }
725
726   return index;
727 }
728
729 extern void srptool_version (void);
730
731 void
732 srptool_version (void)
733 {
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);
739 }