diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-04-03 10:56:36 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-04-03 10:56:36 +0200 |
commit | 4adc232cdc3f5aad1a2be38d8875494561f813cb (patch) | |
tree | 825558e586fcc5a1abc4a362119d5f437a063066 /src/srptool.c | |
parent | 463f925edd6e6b7196a31c4176d4af67d01d0c59 (diff) | |
download | gnutls-4adc232cdc3f5aad1a2be38d8875494561f813cb.tar.gz |
crypt.* renamed to srptool.*.
Diffstat (limited to 'src/srptool.c')
-rw-r--r-- | src/srptool.c | 731 |
1 files changed, 731 insertions, 0 deletions
diff --git a/src/srptool.c b/src/srptool.c new file mode 100644 index 0000000000..187842450a --- /dev/null +++ b/src/srptool.c @@ -0,0 +1,731 @@ +/* + * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + * Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <gnutls/gnutls.h> +#include <gnutls/extra.h> +#include <crypt-gaa.h> +#include "../lib/random.h" /* for random */ + +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef _WIN32 +#include <pwd.h> +#include <unistd.h> +#else +#include <windows.h> +#endif + +/* Gnulib portability files. */ +#include <getpass.h> +#include <minmax.h> +#include <progname.h> +#include <version-etc.h> + +/* This may need some rewrite. A lot of stuff which should be here + * are in the library, which is not good. + */ + +int crypt_int (const char *username, const char *passwd, int salt, + char *tpasswd_conf, char *tpasswd, int uindex); +static int read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, + char *str); +static int _verify_passwd_int (const char *username, const char *passwd, + char *verifier, char *salt, + const gnutls_datum_t * g, + const gnutls_datum_t * n); + +static void +print_num (const char *msg, const gnutls_datum_t * num) +{ + unsigned int i; + + printf ("%s:\t", msg); + + for (i = 0; i < num->size; i++) + { + if (i != 0 && i % 12 == 0) + printf ("\n\t"); + else if (i != 0 && i != num->size) + printf (":"); + printf ("%.2x", num->data[i]); + } + printf ("\n\n"); + +} + +static int +generate_create_conf (char *tpasswd_conf) +{ + FILE *fd; + char line[5 * 1024]; + int index = 1; + gnutls_datum_t g, n; + gnutls_datum_t str_g, str_n; + + fd = fopen (tpasswd_conf, "w"); + if (fd == NULL) + { + fprintf (stderr, "Cannot open file '%s'\n", tpasswd_conf); + return -1; + } + + for (index = 1; index <= 3; index++) + { + + if (index == 1) + { + n = gnutls_srp_1024_group_prime; + g = gnutls_srp_1024_group_generator; + } + else if (index == 2) + { + n = gnutls_srp_1536_group_prime; + g = gnutls_srp_1536_group_generator; + } + else + { + n = gnutls_srp_2048_group_prime; + g = gnutls_srp_2048_group_generator; + } + + printf ("\nGroup %d, of %d bits:\n", index, n.size * 8); + print_num ("Generator", &g); + print_num ("Prime", &n); + + if (gnutls_srp_base64_encode_alloc (&n, &str_n) < 0) + { + fprintf (stderr, "Could not encode\n"); + return -1; + } + + if (gnutls_srp_base64_encode_alloc (&g, &str_g) < 0) + { + fprintf (stderr, "Could not encode\n"); + return -1; + } + + sprintf (line, "%d:%s:%s\n", index, str_n.data, str_g.data); + + gnutls_free (str_n.data); + gnutls_free (str_g.data); + + fwrite (line, 1, strlen (line), fd); + + } + + fclose (fd); + + return 0; + +} + +/* The format of a tpasswd file is: + * username:verifier:salt:index + * + * index is the index of the prime-generator pair in tpasswd.conf + */ +static int +_verify_passwd_int (const char *username, const char *passwd, + char *verifier, char *salt, + const gnutls_datum_t * g, const gnutls_datum_t * n) +{ + char _salt[1024]; + gnutls_datum_t tmp, raw_salt, new_verifier; + size_t salt_size; + char *pos; + + if (salt == NULL || verifier == NULL) + return -1; + + /* copy salt, and null terminate after the ':' */ + strcpy (_salt, salt); + pos = strchr (_salt, ':'); + if (pos != NULL) + *pos = 0; + + /* convert salt to binary. */ + tmp.data = _salt; + tmp.size = strlen (_salt); + + if (gnutls_srp_base64_decode_alloc (&tmp, &raw_salt) < 0) + { + fprintf (stderr, "Could not decode salt.\n"); + return -1; + } + + if (gnutls_srp_verifier + (username, passwd, &raw_salt, g, n, &new_verifier) < 0) + { + fprintf (stderr, "Could not make the verifier\n"); + return -1; + } + + free (raw_salt.data); + + /* encode the verifier into _salt */ + salt_size = sizeof (_salt); + memset (_salt, 0, salt_size); + if (gnutls_srp_base64_encode (&new_verifier, _salt, &salt_size) < 0) + { + fprintf (stderr, "Encoding error\n"); + return -1; + } + + free (new_verifier.data); + + if (strncmp (verifier, _salt, strlen (_salt)) == 0) + { + fprintf (stderr, "Password verified\n"); + return 0; + } + else + { + fprintf (stderr, "Password does NOT match\n"); + } + return -1; +} + +static int +filecopy (char *src, char *dst) +{ + FILE *fd, *fd2; + char line[5 * 1024]; + char *p; + + fd = fopen (dst, "w"); + if (fd == NULL) + { + fprintf (stderr, "Cannot open '%s' for write\n", dst); + return -1; + } + + fd2 = fopen (src, "r"); + if (fd2 == NULL) + { + /* empty file */ + fclose (fd); + return 0; + } + + line[sizeof (line) - 1] = 0; + do + { + p = fgets (line, sizeof (line) - 1, fd2); + if (p == NULL) + break; + + fputs (line, fd); + } + while (1); + + fclose (fd); + fclose (fd2); + + return 0; +} + +/* accepts password file */ +static int +find_strchr (char *username, char *file) +{ + FILE *fd; + char *pos; + char line[5 * 1024]; + unsigned int i; + + fd = fopen (file, "r"); + if (fd == NULL) + { + fprintf (stderr, "Cannot open file '%s'\n", file); + return -1; + } + + while (fgets (line, sizeof (line), fd) != NULL) + { + /* move to first ':' */ + i = 0; + while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line))) + { + i++; + } + if (strncmp (username, line, MAX (i, strlen (username))) == 0) + { + /* find the index */ + pos = strrchr (line, ':'); + pos++; + fclose (fd); + return atoi (pos); + } + } + + fclose (fd); + return -1; +} + +/* Parses the tpasswd files, in order to verify the given + * username/password pair. + */ +static int +verify_passwd (char *conffile, char *tpasswd, char *username, + const char *passwd) +{ + FILE *fd; + char line[5 * 1024]; + unsigned int i; + gnutls_datum_t g, n; + int iindex; + char *p, *pos; + + iindex = find_strchr (username, tpasswd); + if (iindex == -1) + { + fprintf (stderr, "Cannot find '%s' in %s\n", username, tpasswd); + return -1; + } + + fd = fopen (conffile, "r"); + if (fd == NULL) + { + fprintf (stderr, "Cannot find %s\n", conffile); + return -1; + } + + do + { + p = fgets (line, sizeof (line) - 1, fd); + } + while (p != NULL && atoi (p) != iindex); + + if (p == NULL) + { + fprintf (stderr, "Cannot find entry in %s\n", conffile); + return -1; + } + line[sizeof (line) - 1] = 0; + + fclose (fd); + + if ((iindex = read_conf_values (&g, &n, line)) < 0) + { + fprintf (stderr, "Cannot parse conf file '%s'\n", conffile); + return -1; + } + + fd = fopen (tpasswd, "r"); + if (fd == NULL) + { + fprintf (stderr, "Cannot open file '%s'\n", tpasswd); + return -1; + } + + while (fgets (line, sizeof (line), fd) != NULL) + { + /* move to first ':' + * This is the actual verifier. + */ + i = 0; + while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof (line))) + { + i++; + } + if (strncmp (username, line, MAX (i, strlen (username))) == 0) + { + char *verifier_pos, *salt_pos; + + pos = strchr (line, ':'); + fclose (fd); + if (pos == NULL) + { + fprintf (stderr, "Cannot parse conf file '%s'\n", conffile); + return -1; + } + pos++; + verifier_pos = pos; + + /* Move to the salt */ + pos = strchr (pos, ':'); + if (pos == NULL) + { + fprintf (stderr, "Cannot parse conf file '%s'\n", conffile); + return -1; + } + pos++; + salt_pos = pos; + + return _verify_passwd_int (username, passwd, + verifier_pos, salt_pos, &g, &n); + } + } + + fclose (fd); + return -1; + +} + +#define KPASSWD "/etc/tpasswd" +#define KPASSWD_CONF "/etc/tpasswd.conf" + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "|<%d>| %s", level, str); +} + +int main (int argc, char **argv) +{ + gaainfo info; + const char *passwd; + int salt_size, ret; + struct passwd *pwd; + + set_program_name (argv[0]); + + if ((ret = gnutls_global_init ()) < 0) + { + fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret)); + exit (1); + } + + umask (066); + + if (gaa (argc, argv, &info) != -1) + { + fprintf (stderr, "Error in the arguments.\n"); + return -1; + } + + gnutls_global_set_log_function (tls_log_func); + gnutls_global_set_log_level (info.debug); + + if (info.create_conf != NULL) + { + return generate_create_conf (info.create_conf); + } + + if (info.passwd == NULL) + info.passwd = (char *) KPASSWD; + if (info.passwd_conf == NULL) + info.passwd_conf = (char *) KPASSWD_CONF; + + if (info.username == NULL) + { +#ifndef _WIN32 + pwd = getpwuid (getuid ()); + + if (pwd == NULL) + { + fprintf (stderr, "No such user\n"); + return -1; + } + + info.username = pwd->pw_name; +#else + fprintf (stderr, "Please specify a user\n"); + return -1; +#endif + } + + salt_size = 16; + + passwd = getpass ("Enter password: "); + if (passwd == NULL) + { + fprintf (stderr, "Please specify a password\n"); + return -1; + } + +/* not ready yet */ + if (info.verify != 0) + { + return verify_passwd (info.passwd_conf, info.passwd, + info.username, passwd); + } + + + return crypt_int (info.username, passwd, salt_size, + info.passwd_conf, info.passwd, info.index); + +} + +static char * +_srp_crypt (const char *username, const char *passwd, int salt_size, + const gnutls_datum_t * g, const gnutls_datum_t * n) +{ + char salt[128]; + static char result[1024]; + gnutls_datum_t dat_salt, txt_salt; + gnutls_datum_t verifier, txt_verifier; + + if ((unsigned) salt_size > sizeof (salt)) + return NULL; + + /* generate the salt + */ + if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0) + { + fprintf (stderr, "Could not create nonce\n"); + return NULL; + } + + dat_salt.data = salt; + dat_salt.size = salt_size; + + if (gnutls_srp_verifier (username, passwd, &dat_salt, g, n, &verifier) < 0) + { + fprintf (stderr, "Error getting verifier\n"); + return NULL; + } + + /* base64 encode the verifier */ + if (gnutls_srp_base64_encode_alloc (&verifier, &txt_verifier) < 0) + { + fprintf (stderr, "Error encoding\n"); + free (verifier.data); + return NULL; + } + + free (verifier.data); + + if (gnutls_srp_base64_encode_alloc (&dat_salt, &txt_salt) < 0) + { + fprintf (stderr, "Error encoding\n"); + return NULL; + } + + sprintf (result, "%s:%s", txt_verifier.data, txt_salt.data); + free (txt_salt.data); + free (txt_verifier.data); + + return result; + +} + + +int +crypt_int (const char *username, const char *passwd, int salt_size, + char *tpasswd_conf, char *tpasswd, int uindex) +{ + FILE *fd; + char *cr; + gnutls_datum_t g, n; + char line[5 * 1024]; + char *p, *pp; + int iindex; + char tmpname[1024]; + + fd = fopen (tpasswd_conf, "r"); + if (fd == NULL) + { + fprintf (stderr, "Cannot find %s\n", tpasswd_conf); + return -1; + } + + do + { /* find the specified uindex in file */ + p = fgets (line, sizeof (line) - 1, fd); + iindex = atoi (p); + } + while (p != NULL && iindex != uindex); + + if (p == NULL) + { + fprintf (stderr, "Cannot find entry in %s\n", tpasswd_conf); + return -1; + } + line[sizeof (line) - 1] = 0; + + fclose (fd); + if ((iindex = read_conf_values (&g, &n, line)) < 0) + { + fprintf (stderr, "Cannot parse conf file '%s'\n", tpasswd_conf); + return -1; + } + + cr = _srp_crypt (username, passwd, salt_size, &g, &n); + if (cr == NULL) + { + fprintf (stderr, "Cannot _srp_crypt()...\n"); + return -1; + } + else + { + /* delete previous entry */ + struct stat st; + FILE *fd2; + int put; + + if (strlen (tpasswd) > sizeof (tmpname) + 5) + { + fprintf (stderr, "file '%s' is tooooo long\n", tpasswd); + return -1; + } + strcpy (tmpname, tpasswd); + strcat (tmpname, ".tmp"); + + if (stat (tmpname, &st) != -1) + { + fprintf (stderr, "file '%s' is locked\n", tpasswd); + return -1; + } + + if (filecopy (tpasswd, tmpname) != 0) + { + fprintf (stderr, "Cannot copy '%s' to '%s'\n", tpasswd, tmpname); + return -1; + } + + fd = fopen (tpasswd, "w"); + if (fd == NULL) + { + fprintf (stderr, "Cannot open '%s' for write\n", tpasswd); + remove (tmpname); + return -1; + } + + fd2 = fopen (tmpname, "r"); + if (fd2 == NULL) + { + fprintf (stderr, "Cannot open '%s' for read\n", tmpname); + remove (tmpname); + return -1; + } + + put = 0; + do + { + p = fgets (line, sizeof (line) - 1, fd2); + if (p == NULL) + break; + + pp = strchr (line, ':'); + if (pp == NULL) + continue; + + if (strncmp (p, username, + MAX (strlen (username), (unsigned int) (pp - p))) == 0) + { + put = 1; + fprintf (fd, "%s:%s:%u\n", username, cr, iindex); + } + else + { + fputs (line, fd); + } + } + while (1); + + if (put == 0) + { + fprintf (fd, "%s:%s:%u\n", username, cr, iindex); + } + + fclose (fd); + fclose (fd2); + + remove (tmpname); + + } + + + return 0; +} + + + +/* this function parses tpasswd.conf file. Format is: + * int(index):base64(n):base64(g) + */ +static int +read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n, char *str) +{ + char *p; + int len; + int index, ret; + gnutls_datum_t dat; + + index = atoi (str); + + p = strrchr (str, ':'); /* we have g */ + if (p == NULL) + { + return -1; + } + + *p = '\0'; + p++; + + /* read the generator */ + len = strlen (p); + if (p[len - 1] == '\n') + len--; + + dat.data = p; + dat.size = len; + ret = gnutls_srp_base64_decode_alloc (&dat, g); + + if (ret < 0) + { + fprintf (stderr, "Decoding error\n"); + return -1; + } + + /* now go for n - modulo */ + p = strrchr (str, ':'); /* we have n */ + if (p == NULL) + { + return -1; + } + + *p = '\0'; + p++; + + dat.data = p; + dat.size = strlen (p); + + ret = gnutls_srp_base64_decode_alloc (&dat, n); + + if (ret < 0) + { + fprintf (stderr, "Decoding error\n"); + free (g->data); + return -1; + } + + return index; +} + +extern void srptool_version (void); + +void +srptool_version (void) +{ + const char *p = PACKAGE_NAME; + if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0) + p = PACKAGE_STRING; + version_etc (stdout, "srptool", p, gnutls_check_version (NULL), + "Nikos Mavrogiannopoulos", (char *) NULL); +} |