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/>.
26 #include <gnutls/gnutls.h>
27 #include <gnutls/crypto.h> /* for random */
29 #include <sys/types.h>
39 /* Gnulib portability files. */
43 #include <version-etc.h>
45 #include <srptool-args.h>
47 /* This may need some rewrite. A lot of stuff which should be here
48 * are in the library, which is not good.
51 int crypt_int (const char *username
, const char *passwd
, int salt
,
52 const char *tpasswd_conf
, const char *tpasswd
, int uindex
);
53 static int read_conf_values (gnutls_datum_t
* g
, gnutls_datum_t
* n
,
55 static int _verify_passwd_int (const char *username
, const char *passwd
,
56 char *verifier
, const char *salt
,
57 const gnutls_datum_t
* g
,
58 const gnutls_datum_t
* n
);
61 print_num (const char *msg
, const gnutls_datum_t
* num
)
65 printf ("%s:\t", msg
);
67 for (i
= 0; i
< num
->size
; i
++)
69 if (i
!= 0 && i
% 12 == 0)
71 else if (i
!= 0 && i
!= num
->size
)
73 printf ("%.2x", num
->data
[i
]);
80 generate_create_conf (const char *tpasswd_conf
)
86 gnutls_datum_t str_g
, str_n
;
88 fd
= fopen (tpasswd_conf
, "w");
91 fprintf (stderr
, "Cannot open file '%s'\n", tpasswd_conf
);
95 for (index
= 1; index
<= 5; index
++)
100 n
= gnutls_srp_1024_group_prime
;
101 g
= gnutls_srp_1024_group_generator
;
105 n
= gnutls_srp_1536_group_prime
;
106 g
= gnutls_srp_1536_group_generator
;
110 n
= gnutls_srp_2048_group_prime
;
111 g
= gnutls_srp_2048_group_generator
;
115 n
= gnutls_srp_3072_group_prime
;
116 g
= gnutls_srp_3072_group_generator
;
120 n
= gnutls_srp_4096_group_prime
;
121 g
= gnutls_srp_4096_group_generator
;
125 fprintf(stderr
, "Unknown index: %d\n", index
);
129 printf ("\nGroup %d, of %d bits:\n", index
, n
.size
* 8);
130 print_num ("Generator", &g
);
131 print_num ("Prime", &n
);
133 if (gnutls_srp_base64_encode_alloc (&n
, &str_n
) < 0)
135 fprintf (stderr
, "Could not encode\n");
139 if (gnutls_srp_base64_encode_alloc (&g
, &str_g
) < 0)
141 fprintf (stderr
, "Could not encode\n");
145 sprintf (line
, "%d:%s:%s\n", index
, str_n
.data
, str_g
.data
);
147 gnutls_free (str_n
.data
);
148 gnutls_free (str_g
.data
);
150 fwrite (line
, 1, strlen (line
), fd
);
160 /* The format of a tpasswd file is:
161 * username:verifier:salt:index
163 * index is the index of the prime-generator pair in tpasswd.conf
166 _verify_passwd_int (const char *username
, const char *passwd
,
167 char *verifier
, const char *salt
,
168 const gnutls_datum_t
* g
, const gnutls_datum_t
* n
)
171 gnutls_datum_t tmp
, raw_salt
, new_verifier
;
175 if (salt
== NULL
|| verifier
== NULL
)
178 if (strlen(salt
) >= sizeof(_salt
))
180 fprintf (stderr
, "Too long salt.\n");
184 /* copy salt, and null terminate after the ':' */
185 strcpy (_salt
, salt
);
186 pos
= strchr (_salt
, ':');
190 /* convert salt to binary. */
191 tmp
.data
= (void*)_salt
;
192 tmp
.size
= strlen (_salt
);
194 if (gnutls_srp_base64_decode_alloc (&tmp
, &raw_salt
) < 0)
196 fprintf (stderr
, "Could not decode salt.\n");
200 if (gnutls_srp_verifier
201 (username
, passwd
, &raw_salt
, g
, n
, &new_verifier
) < 0)
203 fprintf (stderr
, "Could not make the verifier\n");
207 free (raw_salt
.data
);
209 /* encode the verifier into _salt */
210 salt_size
= sizeof (_salt
);
211 memset (_salt
, 0, salt_size
);
212 if (gnutls_srp_base64_encode (&new_verifier
, _salt
, &salt_size
) < 0)
214 fprintf (stderr
, "Encoding error\n");
218 free (new_verifier
.data
);
220 if (strncmp (verifier
, _salt
, strlen (_salt
)) == 0)
222 fprintf (stderr
, "Password verified\n");
227 fprintf (stderr
, "Password does NOT match\n");
233 filecopy (const char *src
, const char *dst
)
239 fd
= fopen (dst
, "w");
242 fprintf (stderr
, "Cannot open '%s' for write\n", dst
);
246 fd2
= fopen (src
, "r");
254 line
[sizeof (line
) - 1] = 0;
257 p
= fgets (line
, sizeof (line
) - 1, fd2
);
271 /* accepts password file */
273 find_strchr (const char *username
, const char *file
)
280 fd
= fopen (file
, "r");
283 fprintf (stderr
, "Cannot open file '%s'\n", file
);
287 while (fgets (line
, sizeof (line
), fd
) != NULL
)
289 /* move to first ':' */
291 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
295 if (strncmp (username
, line
, MAX (i
, strlen (username
))) == 0)
298 pos
= strrchr (line
, ':');
309 /* Parses the tpasswd files, in order to verify the given
310 * username/password pair.
313 verify_passwd (const char *conffile
, const char *tpasswd
,
314 const char *username
, const char *passwd
)
323 iindex
= find_strchr (username
, tpasswd
);
326 fprintf (stderr
, "Cannot find '%s' in %s\n", username
, tpasswd
);
330 fd
= fopen (conffile
, "r");
333 fprintf (stderr
, "Cannot find %s\n", conffile
);
339 p
= fgets (line
, sizeof (line
) - 1, fd
);
341 while (p
!= NULL
&& atoi (p
) != iindex
);
345 fprintf (stderr
, "Cannot find entry in %s\n", conffile
);
348 line
[sizeof (line
) - 1] = 0;
352 if ((iindex
= read_conf_values (&g
, &n
, line
)) < 0)
354 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
358 fd
= fopen (tpasswd
, "r");
361 fprintf (stderr
, "Cannot open file '%s'\n", tpasswd
);
365 while (fgets (line
, sizeof (line
), fd
) != NULL
)
368 * This is the actual verifier.
371 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
375 if (strncmp (username
, line
, MAX (i
, strlen (username
))) == 0)
377 char *verifier_pos
, *salt_pos
;
379 pos
= strchr (line
, ':');
383 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
389 /* Move to the salt */
390 pos
= strchr (pos
, ':');
393 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
399 return _verify_passwd_int (username
, passwd
,
400 verifier_pos
, salt_pos
, &g
, &n
);
409 #define KPASSWD "/etc/tpasswd"
410 #define KPASSWD_CONF "/etc/tpasswd.conf"
413 tls_log_func (int level
, const char *str
)
415 fprintf (stderr
, "|<%d>| %s", level
, str
);
418 int main (int argc
, char **argv
)
423 const char* fpasswd
, *fpasswd_conf
;
424 const char* username
;
429 set_program_name (argv
[0]);
431 if ((ret
= gnutls_global_init ()) < 0)
433 fprintf (stderr
, "global_init: %s\n", gnutls_strerror (ret
));
439 optct
= optionProcess( &srptoolOptions
, argc
, argv
);
443 gnutls_global_set_log_function (tls_log_func
);
444 gnutls_global_set_log_level (OPT_VALUE_DEBUG
);
446 if (HAVE_OPT(CREATE_CONF
))
448 return generate_create_conf (OPT_ARG(CREATE_CONF
));
451 if (HAVE_OPT(PASSWD
))
452 fpasswd
= OPT_ARG(PASSWD
);
454 fpasswd
= (char *) KPASSWD
;
456 if (HAVE_OPT(PASSWD_CONF
))
457 fpasswd_conf
= OPT_ARG(PASSWD_CONF
);
459 fpasswd_conf
= (char *) KPASSWD_CONF
;
461 if (HAVE_OPT(USERNAME
))
462 username
= OPT_ARG(USERNAME
);
466 pwd
= getpwuid (getuid ());
470 fprintf (stderr
, "No such user\n");
474 username
= pwd
->pw_name
;
476 fprintf (stderr
, "Please specify a user\n");
483 passwd
= getpass ("Enter password: ");
486 fprintf (stderr
, "Please specify a password\n");
491 if (HAVE_OPT(VERIFY
))
493 return verify_passwd (fpasswd_conf
, fpasswd
,
498 return crypt_int (username
, passwd
, salt_size
,
499 fpasswd_conf
, fpasswd
, VALUE_OPT_INDEX
);
504 _srp_crypt (const char *username
, const char *passwd
, int salt_size
,
505 const gnutls_datum_t
* g
, const gnutls_datum_t
* n
)
507 unsigned char salt
[128];
508 static char result
[1024];
509 gnutls_datum_t dat_salt
, txt_salt
;
510 gnutls_datum_t verifier
, txt_verifier
;
512 if ((unsigned) salt_size
> sizeof (salt
))
517 if (gnutls_rnd (GNUTLS_RND_NONCE
, salt
, salt_size
) < 0)
519 fprintf (stderr
, "Could not create nonce\n");
523 dat_salt
.data
= salt
;
524 dat_salt
.size
= salt_size
;
526 if (gnutls_srp_verifier (username
, passwd
, &dat_salt
, g
, n
, &verifier
) < 0)
528 fprintf (stderr
, "Error getting verifier\n");
532 /* base64 encode the verifier */
533 if (gnutls_srp_base64_encode_alloc (&verifier
, &txt_verifier
) < 0)
535 fprintf (stderr
, "Error encoding\n");
536 free (verifier
.data
);
540 free (verifier
.data
);
542 if (gnutls_srp_base64_encode_alloc (&dat_salt
, &txt_salt
) < 0)
544 fprintf (stderr
, "Error encoding\n");
548 sprintf (result
, "%s:%s", txt_verifier
.data
, txt_salt
.data
);
549 free (txt_salt
.data
);
550 free (txt_verifier
.data
);
558 crypt_int (const char *username
, const char *passwd
, int salt_size
,
559 const char *tpasswd_conf
, const char *tpasswd
, int uindex
)
569 fd
= fopen (tpasswd_conf
, "r");
572 fprintf (stderr
, "Cannot find %s\n", tpasswd_conf
);
577 { /* find the specified uindex in file */
578 p
= fgets (line
, sizeof (line
) - 1, fd
);
581 while (p
!= NULL
&& iindex
!= uindex
);
585 fprintf (stderr
, "Cannot find entry in %s\n", tpasswd_conf
);
588 line
[sizeof (line
) - 1] = 0;
591 if ((iindex
= read_conf_values (&g
, &n
, line
)) < 0)
593 fprintf (stderr
, "Cannot parse conf file '%s'\n", tpasswd_conf
);
597 cr
= _srp_crypt (username
, passwd
, salt_size
, &g
, &n
);
600 fprintf (stderr
, "Cannot _srp_crypt()...\n");
605 /* delete previous entry */
610 if (strlen (tpasswd
) > sizeof (tmpname
) + 5)
612 fprintf (stderr
, "file '%s' is tooooo long\n", tpasswd
);
615 strcpy (tmpname
, tpasswd
);
616 strcat (tmpname
, ".tmp");
618 if (stat (tmpname
, &st
) != -1)
620 fprintf (stderr
, "file '%s' is locked\n", tpasswd
);
624 if (filecopy (tpasswd
, tmpname
) != 0)
626 fprintf (stderr
, "Cannot copy '%s' to '%s'\n", tpasswd
, tmpname
);
630 fd
= fopen (tpasswd
, "w");
633 fprintf (stderr
, "Cannot open '%s' for write\n", tpasswd
);
638 fd2
= fopen (tmpname
, "r");
641 fprintf (stderr
, "Cannot open '%s' for read\n", tmpname
);
649 p
= fgets (line
, sizeof (line
) - 1, fd2
);
653 pp
= strchr (line
, ':');
657 if (strncmp (p
, username
,
658 MAX (strlen (username
), (unsigned int) (pp
- p
))) == 0)
661 fprintf (fd
, "%s:%s:%u\n", username
, cr
, iindex
);
672 fprintf (fd
, "%s:%s:%u\n", username
, cr
, iindex
);
688 /* this function parses tpasswd.conf file. Format is:
689 * int(index):base64(n):base64(g)
692 read_conf_values (gnutls_datum_t
* g
, gnutls_datum_t
* n
, char *str
)
701 p
= strrchr (str
, ':'); /* we have g */
710 /* read the generator */
712 if (p
[len
- 1] == '\n')
717 ret
= gnutls_srp_base64_decode_alloc (&dat
, g
);
721 fprintf (stderr
, "Decoding error\n");
725 /* now go for n - modulo */
726 p
= strrchr (str
, ':'); /* we have n */
736 dat
.size
= strlen (p
);
738 ret
= gnutls_srp_base64_decode_alloc (&dat
, n
);
742 fprintf (stderr
, "Decoding error\n");