summaryrefslogtreecommitdiff
path: root/src/srptool.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-03 10:56:36 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-03 10:56:36 +0200
commit4adc232cdc3f5aad1a2be38d8875494561f813cb (patch)
tree825558e586fcc5a1abc4a362119d5f437a063066 /src/srptool.c
parent463f925edd6e6b7196a31c4176d4af67d01d0c59 (diff)
downloadgnutls-4adc232cdc3f5aad1a2be38d8875494561f813cb.tar.gz
crypt.* renamed to srptool.*.
Diffstat (limited to 'src/srptool.c')
-rw-r--r--src/srptool.c731
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);
+}