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 <srptool-args.h>
45 /* This may need some rewrite. A lot of stuff which should be here
46 * are in the library, which is not good.
49 int crypt_int(const char *username, const char *passwd, int salt,
50 const char *tpasswd_conf, const char *tpasswd, int uindex);
51 static int read_conf_values(gnutls_datum_t * g, gnutls_datum_t * n,
53 static int _verify_passwd_int(const char *username, const char *passwd,
54 char *verifier, const char *salt,
55 const gnutls_datum_t * g,
56 const gnutls_datum_t * n);
58 static void print_num(const char *msg, const gnutls_datum_t * num)
64 for (i = 0; i < num->size; i++) {
65 if (i != 0 && i % 12 == 0)
67 else if (i != 0 && i != num->size)
69 printf("%.2x", num->data[i]);
75 static int generate_create_conf(const char *tpasswd_conf)
81 gnutls_datum_t str_g, str_n;
83 fd = fopen(tpasswd_conf, "w");
85 fprintf(stderr, "Cannot open file '%s'\n", tpasswd_conf);
89 for (index = 1; index <= 5; index++) {
92 n = gnutls_srp_1024_group_prime;
93 g = gnutls_srp_1024_group_generator;
94 } else if (index == 2) {
95 n = gnutls_srp_1536_group_prime;
96 g = gnutls_srp_1536_group_generator;
97 } else if (index == 3) {
98 n = gnutls_srp_2048_group_prime;
99 g = gnutls_srp_2048_group_generator;
100 } else if (index == 4) {
101 n = gnutls_srp_3072_group_prime;
102 g = gnutls_srp_3072_group_generator;
103 } else if (index == 5) {
104 n = gnutls_srp_4096_group_prime;
105 g = gnutls_srp_4096_group_generator;
107 fprintf(stderr, "Unknown index: %d\n", index);
111 printf("\nGroup %d, of %d bits:\n", index, n.size * 8);
112 print_num("Generator", &g);
113 print_num("Prime", &n);
115 if (gnutls_srp_base64_encode_alloc(&n, &str_n) < 0) {
116 fprintf(stderr, "Could not encode\n");
121 if (gnutls_srp_base64_encode_alloc(&g, &str_g) < 0) {
122 fprintf(stderr, "Could not encode\n");
127 sprintf(line, "%d:%s:%s\n", index, str_n.data, str_g.data);
129 gnutls_free(str_n.data);
130 gnutls_free(str_g.data);
132 fwrite(line, 1, strlen(line), fd);
142 /* The format of a tpasswd file is:
143 * username:verifier:salt:index
145 * index is the index of the prime-generator pair in tpasswd.conf
148 _verify_passwd_int(const char *username, const char *passwd,
149 char *verifier, const char *salt,
150 const gnutls_datum_t * g, const gnutls_datum_t * n)
153 gnutls_datum_t tmp, raw_salt, new_verifier;
157 if (salt == NULL || verifier == NULL)
160 if (strlen(salt) >= sizeof(_salt)) {
161 fprintf(stderr, "Too long salt.\n");
165 /* copy salt, and null terminate after the ':' */
167 pos = strchr(_salt, ':');
171 /* convert salt to binary. */
172 tmp.data = (void *) _salt;
173 tmp.size = strlen(_salt);
175 if (gnutls_srp_base64_decode_alloc(&tmp, &raw_salt) < 0) {
176 fprintf(stderr, "Could not decode salt.\n");
180 if (gnutls_srp_verifier
181 (username, passwd, &raw_salt, g, n, &new_verifier) < 0) {
182 fprintf(stderr, "Could not make the verifier\n");
188 /* encode the verifier into _salt */
189 salt_size = sizeof(_salt);
190 memset(_salt, 0, salt_size);
191 if (gnutls_srp_base64_encode(&new_verifier, _salt, &salt_size) < 0) {
192 fprintf(stderr, "Encoding error\n");
196 free(new_verifier.data);
198 if (strncmp(verifier, _salt, strlen(_salt)) == 0) {
199 fprintf(stderr, "Password verified\n");
202 fprintf(stderr, "Password does NOT match\n");
207 static int filecopy(const char *src, const char *dst)
213 fd = fopen(dst, "w");
215 fprintf(stderr, "Cannot open '%s' for write\n", dst);
219 fd2 = fopen(src, "r");
226 line[sizeof(line) - 1] = 0;
228 p = fgets(line, sizeof(line) - 1, fd2);
242 /* accepts password file */
243 static int find_strchr(const char *username, const char *file)
250 fd = fopen(file, "r");
252 fprintf(stderr, "Cannot open file '%s'\n", file);
256 while (fgets(line, sizeof(line), fd) != NULL) {
257 /* move to first ':' */
259 while ((line[i] != ':') && (line[i] != '\0')
260 && (i < sizeof(line))) {
263 if (strncmp(username, line, MAX(i, strlen(username))) == 0) {
265 pos = strrchr(line, ':');
276 /* Parses the tpasswd files, in order to verify the given
277 * username/password pair.
280 verify_passwd(const char *conffile, const char *tpasswd,
281 const char *username, const char *passwd)
290 iindex = find_strchr(username, tpasswd);
292 fprintf(stderr, "Cannot find '%s' in %s\n", username,
297 fd = fopen(conffile, "r");
299 fprintf(stderr, "Cannot find %s\n", conffile);
304 p = fgets(line, sizeof(line) - 1, fd);
306 while (p != NULL && atoi(p) != iindex);
309 fprintf(stderr, "Cannot find entry in %s\n", conffile);
312 line[sizeof(line) - 1] = 0;
316 if ((iindex = read_conf_values(&g, &n, line)) < 0) {
317 fprintf(stderr, "Cannot parse conf file '%s'\n", conffile);
321 fd = fopen(tpasswd, "r");
323 fprintf(stderr, "Cannot open file '%s'\n", tpasswd);
327 while (fgets(line, sizeof(line), fd) != NULL) {
329 * This is the actual verifier.
332 while ((line[i] != ':') && (line[i] != '\0')
333 && (i < sizeof(line))) {
336 if (strncmp(username, line, MAX(i, strlen(username))) == 0) {
337 char *verifier_pos, *salt_pos;
339 pos = strchr(line, ':');
343 "Cannot parse conf file '%s'\n",
350 /* Move to the salt */
351 pos = strchr(pos, ':');
354 "Cannot parse conf file '%s'\n",
361 return _verify_passwd_int(username, passwd,
362 verifier_pos, salt_pos,
372 #define KPASSWD "/etc/tpasswd"
373 #define KPASSWD_CONF "/etc/tpasswd.conf"
375 static void tls_log_func(int level, const char *str)
377 fprintf(stderr, "|<%d>| %s", level, str);
380 int main(int argc, char **argv)
385 const char *fpasswd, *fpasswd_conf;
386 const char *username;
391 if ((ret = gnutls_global_init()) < 0) {
392 fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
398 optct = optionProcess(&srptoolOptions, argc, argv);
402 gnutls_global_set_log_function(tls_log_func);
403 gnutls_global_set_log_level(OPT_VALUE_DEBUG);
405 if (HAVE_OPT(CREATE_CONF)) {
406 return generate_create_conf(OPT_ARG(CREATE_CONF));
409 if (HAVE_OPT(PASSWD))
410 fpasswd = OPT_ARG(PASSWD);
412 fpasswd = (char *) KPASSWD;
414 if (HAVE_OPT(PASSWD_CONF))
415 fpasswd_conf = OPT_ARG(PASSWD_CONF);
417 fpasswd_conf = (char *) KPASSWD_CONF;
419 if (HAVE_OPT(USERNAME))
420 username = OPT_ARG(USERNAME);
423 pwd = getpwuid(getuid());
426 fprintf(stderr, "No such user\n");
430 username = pwd->pw_name;
432 fprintf(stderr, "Please specify a user\n");
439 passwd = getpass("Enter password: ");
440 if (passwd == NULL) {
441 fprintf(stderr, "Please specify a password\n");
446 if (HAVE_OPT(VERIFY)) {
447 return verify_passwd(fpasswd_conf, fpasswd,
452 return crypt_int(username, passwd, salt_size,
453 fpasswd_conf, fpasswd, OPT_VALUE_INDEX);
457 static char *_srp_crypt(const char *username, const char *passwd,
458 int salt_size, const gnutls_datum_t * g,
459 const gnutls_datum_t * n)
461 unsigned char salt[128];
462 static char result[1024];
463 gnutls_datum_t dat_salt, txt_salt;
464 gnutls_datum_t verifier, txt_verifier;
466 if ((unsigned) salt_size > sizeof(salt))
471 if (gnutls_rnd(GNUTLS_RND_NONCE, salt, salt_size) < 0) {
472 fprintf(stderr, "Could not create nonce\n");
476 dat_salt.data = salt;
477 dat_salt.size = salt_size;
479 if (gnutls_srp_verifier
480 (username, passwd, &dat_salt, g, n, &verifier) < 0) {
481 fprintf(stderr, "Error getting verifier\n");
485 /* base64 encode the verifier */
486 if (gnutls_srp_base64_encode_alloc(&verifier, &txt_verifier) < 0) {
487 fprintf(stderr, "Error encoding\n");
494 if (gnutls_srp_base64_encode_alloc(&dat_salt, &txt_salt) < 0) {
495 fprintf(stderr, "Error encoding\n");
499 sprintf(result, "%s:%s", txt_verifier.data, txt_salt.data);
501 free(txt_verifier.data);
509 crypt_int(const char *username, const char *passwd, int salt_size,
510 const char *tpasswd_conf, const char *tpasswd, int uindex)
520 fd = fopen(tpasswd_conf, "r");
522 fprintf(stderr, "Cannot find %s\n", tpasswd_conf);
526 do { /* find the specified uindex in file */
527 p = fgets(line, sizeof(line) - 1, fd);
529 while (p != NULL && (iindex = atoi(p)) != uindex);
532 fprintf(stderr, "Cannot find entry in %s\n", tpasswd_conf);
535 line[sizeof(line) - 1] = 0;
538 if ((iindex = read_conf_values(&g, &n, line)) < 0) {
539 fprintf(stderr, "Cannot parse conf file '%s'\n",
544 cr = _srp_crypt(username, passwd, salt_size, &g, &n);
546 fprintf(stderr, "Cannot _srp_crypt()...\n");
549 /* delete previous entry */
554 if (strlen(tpasswd) + 5 > sizeof(tmpname)) {
555 fprintf(stderr, "file '%s' is tooooo long\n",
560 snprintf(tmpname, sizeof(tmpname), "%s.tmp", tpasswd);
562 if (stat(tmpname, &st) != -1) {
563 fprintf(stderr, "file '%s' is locked\n", tpasswd);
567 if (filecopy(tpasswd, tmpname) != 0) {
568 fprintf(stderr, "Cannot copy '%s' to '%s'\n",
573 fd = fopen(tpasswd, "w");
575 fprintf(stderr, "Cannot open '%s' for write\n",
581 fd2 = fopen(tmpname, "r");
583 fprintf(stderr, "Cannot open '%s' for read\n",
591 p = fgets(line, sizeof(line) - 1, fd2);
595 pp = strchr(line, ':');
599 if (strncmp(p, username,
600 MAX(strlen(username),
601 (unsigned int) (pp - p))) == 0) {
603 fprintf(fd, "%s:%s:%u\n", username, cr,
612 fprintf(fd, "%s:%s:%u\n", username, cr, iindex);
628 /* this function parses tpasswd.conf file. Format is:
629 * int(index):base64(n):base64(g)
632 read_conf_values(gnutls_datum_t * g, gnutls_datum_t * n, char *str)
641 p = strrchr(str, ':'); /* we have g */
649 /* read the generator */
651 if (p[len - 1] == '\n')
654 dat.data = (void *) p;
656 ret = gnutls_srp_base64_decode_alloc(&dat, g);
659 fprintf(stderr, "Decoding error\n");
663 /* now go for n - modulo */
664 p = strrchr(str, ':'); /* we have n */
672 dat.data = (void *) p;
673 dat.size = strlen(p);
675 ret = gnutls_srp_base64_decode_alloc(&dat, n);
678 fprintf(stderr, "Decoding error\n");