diff options
Diffstat (limited to 'src/psk2.c')
-rw-r--r-- | src/psk2.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/src/psk2.c b/src/psk2.c new file mode 100644 index 0000000000..82184db4a0 --- /dev/null +++ b/src/psk2.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2012 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 + * <https://www.gnu.org/licenses/>. + */ + +#include <config.h> + +/* Gnulib portability files. */ + +#ifndef ENABLE_PSK + +#include <stdio.h> + +int main(int argc, char **argv) +{ + printf("\nPSK not supported. This program is a dummy.\n\n"); + return 1; +}; + +#else + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#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 <minmax.h> +#include "getpass.h" + +/* GnuTLS files */ +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> /* for random */ +#include "options.h" + +static struct config { + bool debug; + int keysize; + char *username; + char *pskfile; +} config = { + // default values for config options (if not 0 or NULL) + .keysize = -1, +}; + +static const struct optionw options[] = { + { "debug", &config.debug, parse_bool, -1, 'd', + { "Print debugging messages. (default: off)\n" + } + }, + { "help", NULL, print_help, 0, 'h', + { "Display extended usage information and exit\n" + } + }, + { "pskfile", &config.pskfile, parse_string, 1, 'p', + { "Specify a pre-shared key file\n" + } + }, + { "keysize", &config.keysize, parse_integer, 1, 's', + { "Specify the key size in bytes (default is 32-bytes or 256-bits)\n", + "- it must be in the range:\n", + "0 to 512\n" + } + }, + { "username", &config.pskfile, parse_string, 1, 'u', + { "Specify the username to use\n" + } + }, + { "version", NULL, print_version, -1, 'v', + { "Display the version information and exit\n" + } + }, +}; + +int print_version(option_t opt, const char *val, const char invert) +{ + puts( + "psktool " PACKAGE_VERSION "\n" + "Copyright (C) 2000-2018 Free Software Foundation, and others, all rights reserved.\n" + "This is free software. It is licensed for use, modification and\n" + "redistribution under the terms of the GNU General Public License,\n" + "version 3 or later <https://gnu.org/licenses/gpl.html>\n" + "\n" + "Please send bug reports to: <bugs@gnutls.org>"); + + return -1; // stop processing & exit +} + +int print_help(option_t opt, const char *val, const char invert) +{ + puts( + "psktool - GnuTLS PSK tool\n" + "Usage: psktool [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n"); + + print_options(options, countof(options)); + + puts( + "\n" + "Program that generates random keys for use with TLS-PSK. The keys are\n" + "stored in hexadecimal format in a key file.\n" + "\n" + "Please send bug reports to: <bugs@gnutls.org>"); + + return -1; // stop processing and exit +} + + +static int write_key(const char *username, const char *key, int key_size, + const char *passwd_file); + +#define MAX_KEY_SIZE 512 +int main(int argc, const char **argv) +{ + int ret; +#ifndef _WIN32 + struct passwd *pwd; +#endif + unsigned char key[MAX_KEY_SIZE]; + char hex_key[MAX_KEY_SIZE * 2 + 1]; + int key_size; + gnutls_datum_t dkey; + const char *passwd, *username; + size_t hex_key_size = sizeof(hex_key); + + if ((ret = gnutls_global_init()) < 0) { + fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + umask(066); + + if (parse_command_line(argc, argv, options, countof(options)) < 0) + exit(1); + + if (!config.pskfile) { + fprintf(stderr, "You need to specify a PSK key file\n"); + exit(1); + } else + passwd = config.pskfile; + + if (!config.username) { +#ifndef _WIN32 + pwd = getpwuid(getuid()); + + if (pwd == NULL) { + fprintf(stderr, "No such user\n"); + return -1; + } + + username = pwd->pw_name; +#else + fprintf(stderr, "Please specify a user\n"); + return -1; +#endif + } else + username = config.username; + + if (config.keysize > MAX_KEY_SIZE) { + fprintf(stderr, "Key size is too long\n"); + exit(1); + } + + if (config.keysize < 1) + key_size = 32; + else + key_size = config.keysize; + + printf("Generating a random key for user '%s'\n", username); + + ret = gnutls_rnd(GNUTLS_RND_RANDOM, (char *) key, key_size); + if (ret < 0) { + fprintf(stderr, "Not enough randomness\n"); + exit(1); + } + + dkey.data = key; + dkey.size = key_size; + + ret = gnutls_hex_encode(&dkey, hex_key, &hex_key_size); + if (ret < 0) { + fprintf(stderr, "HEX encoding error\n"); + exit(1); + } + + ret = write_key(username, hex_key, hex_key_size, passwd); + if (ret == 0) + printf("Key stored to %s\n", passwd); + + return ret; +} + +static int filecopy(const char *src, const 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; +} + +static int +write_key(const char *username, const char *key, int key_size, + const char *passwd_file) +{ + FILE *fd; + char line[5 * 1024]; + char *p, *pp; + char tmpname[1024]; + + + /* delete previous entry */ + struct stat st; + FILE *fd2; + int put; + + if (strlen(passwd_file) + 5 > sizeof(tmpname)) { + fprintf(stderr, "file '%s' is tooooo long\n", passwd_file); + return -1; + } + + snprintf(tmpname, sizeof(tmpname), "%s.tmp", passwd_file); + + if (stat(tmpname, &st) != -1) { + fprintf(stderr, "file '%s' is locked\n", tmpname); + return -1; + } + + if (filecopy(passwd_file, tmpname) != 0) { + fprintf(stderr, "Cannot copy '%s' to '%s'\n", passwd_file, + tmpname); + return -1; + } + + fd = fopen(passwd_file, "w"); + if (fd == NULL) { + fprintf(stderr, "Cannot open '%s' for write\n", + passwd_file); + (void)remove(tmpname); + return -1; + } + + fd2 = fopen(tmpname, "r"); + if (fd2 == NULL) { + fprintf(stderr, "Cannot open '%s' for read\n", tmpname); + (void)remove(tmpname); + fclose(fd); + 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\n", username, key); + } else { + fputs(line, fd); + } + } + while (1); + + if (put == 0) { + fprintf(fd, "%s:%s\n", username, key); + } + + fclose(fd); + fclose(fd2); + + (void)remove(tmpname); + + + return 0; +} + +#endif /* ENABLE_PSK */ |