diff --git a/Makefile b/Makefile index 3fd2b56..d7a2cbd 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,11 @@ PYPGMOPTS := ../Python/pypgmopts/pypgmopts LDFLAGS := `pkg-config --libs openssl` -OBJS := luksrku.o editor.o util.o log.o keydb.o file_encryption.o uuid.o argparse_edit.o pgmopts.o openssl.o +OBJS := luksrku.o editor.o util.o log.o keydb.o file_encryption.o uuid.o argparse_edit.o pgmopts.o openssl.o server.o argparse_server.o parsers: $(PYPGMOPTS) -n edit parsers/parser_edit.py + $(PYPGMOPTS) -n server parsers/parser_server.py install: all cp luksrku $(INSTALL_PREFIX)sbin/ diff --git a/argparse_edit.c b/argparse_edit.c index 0203ba4..86c7f51 100644 --- a/argparse_edit.c +++ b/argparse_edit.c @@ -5,7 +5,7 @@ * * Do not edit it by hand, your changes will be overwritten. * - * Generated at: 2019-10-23 09:40:28 + * Generated at: 2019-10-23 10:06:43 */ #include @@ -110,6 +110,8 @@ bool argparse_edit_parse(int argc, char **argv, argparse_edit_callback_t argumen void argparse_edit_show_syntax(void) { fprintf(stderr, "usage: luksrku edit [-v] [filename]\n"); fprintf(stderr, "\n"); + fprintf(stderr, "Edits a luksrks key database.\n"); + fprintf(stderr, "\n"); fprintf(stderr, "positional arguments:\n"); fprintf(stderr, " filename Database file to edit.\n"); fprintf(stderr, "\n"); diff --git a/argparse_edit.h b/argparse_edit.h index fe2ed23..95c00bd 100644 --- a/argparse_edit.h +++ b/argparse_edit.h @@ -5,7 +5,7 @@ * * Do not edit it by hand, your changes will be overwritten. * - * Generated at: 2019-10-23 09:40:28 + * Generated at: 2019-10-23 10:06:43 */ #ifndef __ARGPARSE_EDIT_H__ diff --git a/argparse_server.c b/argparse_server.c new file mode 100644 index 0000000..226b5f9 --- /dev/null +++ b/argparse_server.c @@ -0,0 +1,182 @@ +/* + * This file was AUTO-GENERATED by pypgmopts. + * + * https://github.com/johndoe31415/pypgmopts + * + * Do not edit it by hand, your changes will be overwritten. + * + * Generated at: 2019-10-23 10:06:43 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "argparse_server.h" + +static enum argparse_server_option_t last_parsed_option; +static char last_error_message[256]; +static const char *option_texts[] = { + [ARG_SERVER_PORT] = "-p / --port", + [ARG_SERVER_SILENT] = "-s / --silent", + [ARG_SERVER_VERBOSE] = "-v / --verbose", + [ARG_SERVER_FILENAME] = "filename", +}; + +enum argparse_server_option_internal_t { + ARG_SERVER_PORT_SHORT = 'p', + ARG_SERVER_SILENT_SHORT = 's', + ARG_SERVER_VERBOSE_SHORT = 'v', + ARG_SERVER_PORT_LONG = 1000, + ARG_SERVER_SILENT_LONG = 1001, + ARG_SERVER_VERBOSE_LONG = 1002, + ARG_SERVER_FILENAME_LONG = 1003, +}; + +static void errmsg_callback(const char *errmsg, ...) { + va_list ap; + va_start(ap, errmsg); + vsnprintf(last_error_message, sizeof(last_error_message), errmsg, ap); + va_end(ap); +} + +static void errmsg_option_callback(enum argparse_server_option_t error_option, const char *errmsg, ...) { + last_parsed_option = error_option; + + va_list ap; + va_start(ap, errmsg); + vsnprintf(last_error_message, sizeof(last_error_message), errmsg, ap); + va_end(ap); +} + +bool argparse_server_parse(int argc, char **argv, argparse_server_callback_t argument_callback, argparse_server_plausibilization_callback_t plausibilization_callback) { + last_parsed_option = ARGPARSE_SERVER_NO_OPTION; + const char *short_options = "p:sv"; + struct option long_options[] = { + { "port", required_argument, 0, ARG_SERVER_PORT_LONG }, + { "silent", no_argument, 0, ARG_SERVER_SILENT_LONG }, + { "verbose", no_argument, 0, ARG_SERVER_VERBOSE_LONG }, + { "filename", required_argument, 0, ARG_SERVER_FILENAME_LONG }, + { 0 } + }; + + while (true) { + int optval = getopt_long(argc, argv, short_options, long_options, NULL); + if (optval == -1) { + break; + } + last_error_message[0] = 0; + enum argparse_server_option_internal_t arg = (enum argparse_server_option_internal_t)optval; + switch (arg) { + case ARG_SERVER_PORT_SHORT: + case ARG_SERVER_PORT_LONG: + last_parsed_option = ARG_SERVER_PORT; + if (!argument_callback(ARG_SERVER_PORT, optarg, errmsg_callback)) { + return false; + } + break; + + case ARG_SERVER_SILENT_SHORT: + case ARG_SERVER_SILENT_LONG: + last_parsed_option = ARG_SERVER_SILENT; + if (!argument_callback(ARG_SERVER_SILENT, optarg, errmsg_callback)) { + return false; + } + break; + + case ARG_SERVER_VERBOSE_SHORT: + case ARG_SERVER_VERBOSE_LONG: + last_parsed_option = ARG_SERVER_VERBOSE; + if (!argument_callback(ARG_SERVER_VERBOSE, optarg, errmsg_callback)) { + return false; + } + break; + + default: + last_parsed_option = ARGPARSE_SERVER_NO_OPTION; + errmsg_callback("unrecognized option supplied"); + return false; + } + } + + const int positional_argument_cnt = argc - optind; + last_parsed_option = ARGPARSE_SERVER_POSITIONAL_ARG; + if (positional_argument_cnt != 1) { + errmsg_callback("expected exactly 1 positional argument, but %d given.", positional_argument_cnt); + return false; + } + + int positional_index = optind; + last_parsed_option = ARG_SERVER_FILENAME; + if (!argument_callback(ARG_SERVER_FILENAME, argv[positional_index++], errmsg_callback)) { + return false; + } + + if (plausibilization_callback) { + if (!plausibilization_callback(errmsg_option_callback)) { + return false; + } + } + return true; +} + +void argparse_server_show_syntax(void) { + fprintf(stderr, "usage: luksrku server [-p port] [-s] [-v] filename\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Starts an luksrku key server.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "positional arguments:\n"); + fprintf(stderr, " filename Database file to load keys from.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "optional arguments:\n"); + fprintf(stderr, " -p port, --port port Port that is used for both UDP and TCP communication.\n"); + fprintf(stderr, " Defaults to 23170.\n"); + fprintf(stderr, " -s, --silent Do not answer UDP queries for clients trying to find a\n"); + fprintf(stderr, " key server, only serve key database using TCP.\n"); + fprintf(stderr, " -v, --verbose Increase verbosity. Can be specified multiple times.\n"); +} + +void argparse_server_parse_or_quit(int argc, char **argv, argparse_server_callback_t argument_callback, argparse_server_plausibilization_callback_t plausibilization_callback) { + if (!argparse_server_parse(argc, argv, argument_callback, plausibilization_callback)) { + if (last_parsed_option > ARGPARSE_SERVER_POSITIONAL_ARG) { + if (last_error_message[0]) { + fprintf(stderr, "luksrku server: error parsing argument %s -- %s\n", option_texts[last_parsed_option], last_error_message); + } else { + fprintf(stderr, "luksrku server: error parsing argument %s -- no details available\n", option_texts[last_parsed_option]); + } + } else if (last_parsed_option == ARGPARSE_SERVER_POSITIONAL_ARG) { + fprintf(stderr, "luksrku server: error parsing optional arguments -- %s\n", last_error_message); + } + argparse_server_show_syntax(); + exit(EXIT_FAILURE); + } +} + +#ifdef __ARGPARSE_MAIN__ +/* gcc -D __ARGPARSE_MAIN__ -O2 -Wall -o argparse argparse_server.c +*/ + +static const char *option_enum_to_str(enum argparse_server_option_t option) { + switch (option) { + case ARG_SERVER_PORT: return "ARG_SERVER_PORT"; + case ARG_SERVER_SILENT: return "ARG_SERVER_SILENT"; + case ARG_SERVER_VERBOSE: return "ARG_SERVER_VERBOSE"; + case ARG_SERVER_FILENAME: return "ARG_SERVER_FILENAME"; + } + return "UNKNOWN"; +} + +bool arg_print_callback(enum argparse_server_option_t option, const char *value, argparse_server_errmsg_callback_t errmsg_callback) { + fprintf(stderr, "%s = \"%s\"\n", option_enum_to_str(option), value); + return true; +} + +int main(int argc, char **argv) { + argparse_server_parse_or_quit(argc, argv, arg_print_callback, NULL); + return 0; +} +#endif diff --git a/argparse_server.h b/argparse_server.h new file mode 100644 index 0000000..3b049d1 --- /dev/null +++ b/argparse_server.h @@ -0,0 +1,38 @@ +/* + * This file was AUTO-GENERATED by pypgmopts. + * + * https://github.com/johndoe31415/pypgmopts + * + * Do not edit it by hand, your changes will be overwritten. + * + * Generated at: 2019-10-23 10:06:43 + */ + +#ifndef __ARGPARSE_SERVER_H__ +#define __ARGPARSE_SERVER_H__ + +#include + +#define ARGPARSE_SERVER_DEFAULT_PORT 23170 +#define ARGPARSE_SERVER_DEFAULT_VERBOSE 0 + +#define ARGPARSE_SERVER_NO_OPTION 0 +#define ARGPARSE_SERVER_POSITIONAL_ARG 1 + +enum argparse_server_option_t { + ARG_SERVER_PORT = 2, + ARG_SERVER_SILENT = 3, + ARG_SERVER_VERBOSE = 4, + ARG_SERVER_FILENAME = 5, +}; + +typedef void (*argparse_server_errmsg_callback_t)(const char *errmsg, ...); +typedef void (*argparse_server_errmsg_option_callback_t)(enum argparse_server_option_t error_option, const char *errmsg, ...); +typedef bool (*argparse_server_callback_t)(enum argparse_server_option_t option, const char *value, argparse_server_errmsg_callback_t errmsg_callback); +typedef bool (*argparse_server_plausibilization_callback_t)(argparse_server_errmsg_option_callback_t errmsg_callback); + +bool argparse_server_parse(int argc, char **argv, argparse_server_callback_t argument_callback, argparse_server_plausibilization_callback_t plausibilization_callback); +void argparse_server_show_syntax(void); +void argparse_server_parse_or_quit(int argc, char **argv, argparse_server_callback_t argument_callback, argparse_server_plausibilization_callback_t plausibilization_callback); + +#endif diff --git a/cmdline.c b/cmdline.c deleted file mode 100644 index 2fe93e0..0000000 --- a/cmdline.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - luksrku - Tool to remotely unlock LUKS disks using TLS. - Copyright (C) 2016-2016 Johannes Bauer - - This file is part of luksrku. - - luksrku 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; this program is ONLY licensed under - version 3 of the License, later versions are explicitly excluded. - - luksrku 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 luksrku; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Johannes Bauer -*/ - -#include -#include -#include -#include - -#include "cmdline.h" -#include "global.h" - -enum longopts_t { - LONGOPT_VERBOSE, - LONGOPT_MODE_SERVER, - LONGOPT_MODE_CLIENT, - LONGOPT_PORT, - LONGOPT_KEYDB, - LONGOPT_UNLOCK_CNT, - LONGOPT_MAX_BCAST_ERRS -}; - -void print_syntax(const char *pgmname) { - fprintf(stderr, "%s (-c, --client-mode) (-s, --server-mode) (-k, --keydb=FILE) (-u, --unlock=CNT)\n", pgmname); - fprintf(stderr, " (-p, --port=PORT) (--max-bcast-errs=CNT) (-v, --verbose)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -c, --client-mode Specifies client mode, i.e., that this host will unlock the LUKS\n"); - fprintf(stderr, " disk of a different machine.\n"); - fprintf(stderr, " -s, --server-mode Specifies server mode, i.e., that this host will announce its\n"); - fprintf(stderr, " presence via UDP broadcasts and then receive the LUKS credentials\n"); - fprintf(stderr, " from a peer.\n"); - fprintf(stderr, " -k, --keydb=FILE Gives the binary key database file which will be used. In server\n"); - fprintf(stderr, " mode, this contains only one entry (specifying the UUID of the\n"); - fprintf(stderr, " host, the PSK and the UUIDs and names of the disks to be\n"); - fprintf(stderr, " unlocked), while in client mode this may contain multiple entries\n"); - fprintf(stderr, " (to unlock many different peers) and also contains the LUKS\n"); - fprintf(stderr, " credentials for the respective disks.\n"); - fprintf(stderr, " -u, --unlock=CNT Specifies the maximum number of unlocking actions that are taken.\n"); - fprintf(stderr, " In client mode, this defaults to 1. In server mode, it defaults to\n"); - fprintf(stderr, " infinite (or until all disks have successfully been unlocked).\n"); - fprintf(stderr, " Zero means infinite.\n"); - fprintf(stderr, " -p, --port=PORT Specifies the port on which is listened for UDP broadcasts and\n"); - fprintf(stderr, " also the port on which TCP requests are sent out (the two are\n"); - fprintf(stderr, " always identical). Default port ist 23170.\n"); - fprintf(stderr, " --max-bcast-errs=CNT This is the number of UDP broadcast attempts luksrku will make\n"); - fprintf(stderr, " before giving up. Usually this is because sendto(2) fails when the\n"); - fprintf(stderr, " network is configured improperly. Giving up in this case enables\n"); - fprintf(stderr, " manual key entry. This defaults to 5 tries.\n"); - fprintf(stderr, " -v, --verbose Increase logging verbosity.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "luksrku version: " BUILD_REVISION "\n"); -} - -static void set_default_arguments(struct options_t *options) { - memset(options, 0, sizeof(struct options_t)); - - /* Default port :-) echo -n LUKS | md5sum | cut -c -5 */ - options->port = 23170; - - /* Default, overwritten later by fill_default_arguments() */ - options->unlock_cnt = -1; - - /* Give up after 5 failed broadcast attempts */ - options->max_broadcast_errs = 5; -} - -static void fill_default_arguments(struct options_t *options) { - /* Set default unlock count */ - if (options->unlock_cnt == -1) { - if (options->mode == CLIENT_MODE) { - options->unlock_cnt = 1; - } else if (options->mode == SERVER_MODE) { - options->unlock_cnt = 0; - } - } -} - -static bool check_arguments(const struct options_t *options) { - if (options->mode == UNDEFINED) { - fprintf(stderr, "Must specify client or server mode.\n"); - return false; - } - - if (options->keydbfile == NULL) { - fprintf(stderr, "Must specify a key database file.\n"); - return false; - } - - if ((options->port < 1) || (options->port > 65535)) { - fprintf(stderr, "Valid port range is 1-65535.\n"); - return false; - } - - if (options->unlock_cnt < 0) { - fprintf(stderr, "Unlock count must be a positive integer.\n"); - return false; - } - return true; -} - -bool parse_cmdline_arguments(struct options_t *options, int argc, char **argv) { - set_default_arguments(options); - - struct option long_options[] = { - { "verbose", no_argument, 0, LONGOPT_VERBOSE }, - { "server-mode", no_argument, 0, LONGOPT_MODE_SERVER }, - { "client-mode", no_argument, 0, LONGOPT_MODE_CLIENT }, - { "port", required_argument, 0, LONGOPT_PORT }, - { "keydb", required_argument, 0, LONGOPT_KEYDB }, - { "unlock", required_argument, 0, LONGOPT_UNLOCK_CNT }, - { "max-bcast-errs", required_argument, 0, LONGOPT_MAX_BCAST_ERRS }, - { 0 } - }; - - bool success = true; - bool parse = true; - do { - int c = getopt_long(argc, argv, "vscp:k:u:", long_options, NULL); - switch (c) { - case LONGOPT_VERBOSE: - case 'v': - options->verbose = true; - break; - - case LONGOPT_MODE_SERVER: - case 's': - options->mode = SERVER_MODE; - break; - - case LONGOPT_MODE_CLIENT: - case 'c': - options->mode = CLIENT_MODE; - break; - - case LONGOPT_PORT: - case 'p': - options->port = atoi(optarg); - break; - - case LONGOPT_KEYDB: - case 'k': - options->keydbfile = optarg; - break; - - case LONGOPT_UNLOCK_CNT: - case 'u': - options->unlock_cnt = atoi(optarg); - break; - - case LONGOPT_MAX_BCAST_ERRS: - options->max_broadcast_errs = atoi(optarg); - break; - - case -1: - /* Out of arguments */ - parse = false; - break; - - case '?': - /* Syntax error */ - parse = false; - success = false; - break; - - default: - fprintf(stderr, "Programming error: unexpected getopt return value %d.\n", c); - parse = false; - success = false; - break; - } - } while (parse); - - fill_default_arguments(options); - return success && check_arguments(options); -} diff --git a/cmdline.h b/cmdline.h deleted file mode 100644 index 188025f..0000000 --- a/cmdline.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - luksrku - Tool to remotely unlock LUKS disks using TLS. - Copyright (C) 2016-2016 Johannes Bauer - - This file is part of luksrku. - - luksrku 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; this program is ONLY licensed under - version 3 of the License, later versions are explicitly excluded. - - luksrku 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 luksrku; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Johannes Bauer -*/ - -#ifndef __CMDLINE_H__ -#define __CMDLINE_H__ - -#include - -enum mode_t { - UNDEFINED = 0, - SERVER_MODE, - CLIENT_MODE -}; - -struct options_t { - enum mode_t mode; - int port; - bool verbose; - const char *keydbfile; - int unlock_cnt; - int max_broadcast_errs; -}; - -/*************** AUTO GENERATED SECTION FOLLOWS ***************/ -enum longopts_t; -void print_syntax(const char *pgmname); -bool parse_cmdline_arguments(struct options_t *options, int argc, char **argv); -/*************** AUTO GENERATED SECTION ENDS ***************/ - -#endif diff --git a/editor.c b/editor.c index 454fa9a..3e82dc4 100644 --- a/editor.c +++ b/editor.c @@ -486,13 +486,13 @@ static enum cmd_returncode_t execute_command(const struct editor_command_t *cmd, } } -bool editor_start(const char *edit_filename) { +bool editor_start(const struct pgmopts_edit_t *opts) { struct editor_context_t editor_context = { .running = true, }; - if (edit_filename) { - char *filename = strdup(edit_filename); + if (opts->filename) { + char *filename = strdup(opts->filename); if (!filename) { log_libc(LLVL_ERROR, "Unable to strdup(3)"); return false; diff --git a/editor.h b/editor.h index 990674f..c9970a8 100644 --- a/editor.h +++ b/editor.h @@ -1,8 +1,34 @@ +/* + luksrku - Tool to remotely unlock LUKS disks using TLS. + Copyright (C) 2016-2019 Johannes Bauer + + This file is part of luksrku. + + luksrku 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; this program is ONLY licensed under + version 3 of the License, later versions are explicitly excluded. + + luksrku 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 luksrku; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Johannes Bauer +*/ + #ifndef __EDITOR_H__ #define __EDITOR_H__ +#include +#include "pgmopts.h" + /*************** AUTO GENERATED SECTION FOLLOWS ***************/ -bool editor_start(const char *edit_filename); +bool editor_start(const struct pgmopts_edit_t *opts); /*************** AUTO GENERATED SECTION ENDS ***************/ #endif diff --git a/luksrku.c b/luksrku.c index 66c50dd..dd16028 100644 --- a/luksrku.c +++ b/luksrku.c @@ -30,18 +30,18 @@ #include "pgmopts.h" #include "editor.h" #include "openssl.h" +#include "server.h" #if OPENSSL_VERSION_NUMBER < 0x010100000 #error "luksrku requires at least OpenSSL v1.1 to work." #endif static int main_edit(const struct pgmopts_edit_t *opts) { - editor_start(opts->filename); - return 0; + return editor_start(opts) ? 0 : 1; } static int main_server(const struct pgmopts_server_t *opts) { - return 0; + return keyserver_start(opts) ? 0 : 1; } static int main_client(const struct pgmopts_client_t *opts) { diff --git a/msg.c b/msg.c deleted file mode 100644 index 37d20e4..0000000 --- a/msg.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - luksrku - Tool to remotely unlock LUKS disks using TLS. - Copyright (C) 2016-2016 Johannes Bauer - - This file is part of luksrku. - - luksrku 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; this program is ONLY licensed under - version 3 of the License, later versions are explicitly excluded. - - luksrku 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 luksrku; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Johannes Bauer -*/ - -#include - -#include "msg.h" - -void msg_to_nbo(struct msg_t *msg) { - msg->passphrase_length = htonl(msg->passphrase_length); -} - -void msg_to_hbo(struct msg_t *msg) { - msg->passphrase_length = ntohl(msg->passphrase_length); -} - diff --git a/msg.h b/msg.h index b664600..46d8a80 100644 --- a/msg.h +++ b/msg.h @@ -33,16 +33,10 @@ struct announcement_t { } __attribute__ ((packed)); struct msg_t { - uint8_t disk_uuid[16]; - uint32_t passphrase_length; - uint8_t passphrase[MAX_PASSPHRASE_LENGTH]; + uint8_t volume_uuid[16]; + uint8_t luks_passphrase_raw[LUKS_PASSPHRASE_RAW_SIZE_BYTES]; } __attribute__ ((packed)); -staticassert(sizeof(struct msg_t) == 16 + 4 + MAX_PASSPHRASE_LENGTH); - -/*************** AUTO GENERATED SECTION FOLLOWS ***************/ -void msg_to_nbo(struct msg_t *msg); -void msg_to_hbo(struct msg_t *msg); -/*************** AUTO GENERATED SECTION ENDS ***************/ +staticassert(sizeof(struct msg_t) == 16 + LUKS_PASSPHRASE_RAW_SIZE_BYTES); #endif diff --git a/openssl.c b/openssl.c index 813e88c..4337043 100644 --- a/openssl.c +++ b/openssl.c @@ -74,17 +74,19 @@ bool create_generic_tls_context(struct generic_tls_ctx_t *gctx, bool server) { const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; SSL_CTX_set_options(gctx->ctx, flags); - if (!SSL_CTX_set_min_proto_version(gctx->ctx, TLS1_2_VERSION)) { + if (!SSL_CTX_set_min_proto_version(gctx->ctx, TLS1_3_VERSION)) { log_openssl(LLVL_FATAL, "Cannot set TLS generic context minimal version."); return false; } - if (!SSL_CTX_set_max_proto_version(gctx->ctx, TLS1_2_VERSION)) { + if (!SSL_CTX_set_max_proto_version(gctx->ctx, TLS1_3_VERSION)) { log_openssl(LLVL_FATAL, "Cannot set TLS generic context maximal version."); return false; } - if (!SSL_CTX_set_cipher_list(gctx->ctx, "ECDHE-PSK-CHACHA20-POLY1305")) { + /* SSL_CTX_set_ciphersuites for TLSv1.3 + * SSL_CTX_set_cipher_list for TLS v1.2 and below */ + if (!SSL_CTX_set_ciphersuites(gctx->ctx, "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384")) { log_openssl(LLVL_FATAL, "Cannot set TLS generic context cipher suites."); return false; } @@ -92,13 +94,14 @@ bool create_generic_tls_context(struct generic_tls_ctx_t *gctx, bool server) { /* In the cipher suite we're using, none of these should be used anyways * (PSK); however for the future we want to have proper crypto here as * well. */ +#if 0 if (!SSL_CTX_set1_sigalgs_list(gctx->ctx, "ECDSA+SHA256:RSA+SHA256:ECDSA+SHA384:RSA+SHA384:ECDSA+SHA512:RSA+SHA512")) { log_openssl(LLVL_FATAL, "Cannot set TLS generic context signature algorithms."); return false; } +#endif - /* TODO: When X448 becomes available, include it here. */ - if (!SSL_CTX_set1_curves_list(gctx->ctx, "X25519")) { + if (!SSL_CTX_set1_curves_list(gctx->ctx, "X448:X25519")) { log_openssl(LLVL_FATAL, "Cannot set TLS generic context ECDHE curves."); return false; } diff --git a/parsers/parser_edit.py b/parsers/parser_edit.py index 599b34a..4d146e7 100755 --- a/parsers/parser_edit.py +++ b/parsers/parser_edit.py @@ -1,4 +1,4 @@ import argparse -parser = argparse.ArgumentParser(prog = "luksrku edit", description = "", add_help = False) +parser = argparse.ArgumentParser(prog = "luksrku edit", description = "Edits a luksrks key database.", add_help = False) parser.add_argument("-v", "--verbose", action = "count", default = 0, help = "Increase verbosity. Can be specified multiple times.") parser.add_argument("filename", metavar = "filename", nargs = "?", type = str, help = "Database file to edit.") diff --git a/parsers/parser_server.py b/parsers/parser_server.py new file mode 100755 index 0000000..97b7951 --- /dev/null +++ b/parsers/parser_server.py @@ -0,0 +1,6 @@ +import argparse +parser = argparse.ArgumentParser(prog = "luksrku server", description = "Starts an luksrku key server.", add_help = False) +parser.add_argument("-p", "--port", metavar = "port", default = 23170, help = "Port that is used for both UDP and TCP communication. Defaults to %(default)d.") +parser.add_argument("-s", "--silent", action = "store_true", help = "Do not answer UDP queries for clients trying to find a key server, only serve key database using TCP.") +parser.add_argument("-v", "--verbose", action = "count", default = 0, help = "Increase verbosity. Can be specified multiple times.") +parser.add_argument("filename", metavar = "filename", help = "Database file to load keys from.") diff --git a/pgmopts.c b/pgmopts.c index 2b2dfcf..ab1d6b9 100644 --- a/pgmopts.c +++ b/pgmopts.c @@ -24,9 +24,11 @@ #include #include #include +#include #include #include "pgmopts.h" #include "argparse_edit.h" +#include "argparse_server.h" static struct pgmopts_t pgmopts_rw = { }; @@ -46,6 +48,9 @@ static void show_syntax(const char *errmsg, int argc, char **argv) { } static bool edit_callback(enum argparse_edit_option_t option, const char *value, argparse_edit_errmsg_callback_t errmsg_callback) { + pgmopts_rw.edit = (struct pgmopts_edit_t){ + .verbosity = ARGPARSE_EDIT_DEFAULT_VERBOSE, + }; switch (option) { case ARG_EDIT_FILENAME: pgmopts_rw.edit.filename = value; @@ -58,10 +63,40 @@ static bool edit_callback(enum argparse_edit_option_t option, const char *value, return true; } +static bool server_callback(enum argparse_server_option_t option, const char *value, argparse_server_errmsg_callback_t errmsg_callback) { + pgmopts_rw.server = (struct pgmopts_server_t){ + .port = ARGPARSE_SERVER_DEFAULT_PORT, + .verbosity = ARGPARSE_SERVER_DEFAULT_VERBOSE, + .answer_udp_queries = true, + }; + switch (option) { + case ARG_SERVER_FILENAME: + pgmopts_rw.server.filename = value; + break; + + case ARG_SERVER_PORT: + pgmopts_rw.server.port = atoi(value); + break; + + case ARG_SERVER_SILENT: + pgmopts_rw.server.answer_udp_queries = false; + break; + + case ARG_SERVER_VERBOSE: + pgmopts_rw.server.verbosity++; + break; + } + return true; +} + static void parse_pgmopts_edit(int argc, char **argv) { argparse_edit_parse_or_quit(argc - 1, argv + 1, edit_callback, NULL); } +static void parse_pgmopts_server(int argc, char **argv) { + argparse_server_parse_or_quit(argc - 1, argv + 1, server_callback, NULL); +} + void parse_pgmopts_or_quit(int argc, char **argv) { if (argc < 2) { show_syntax("no command supplied", argc, argv); @@ -69,9 +104,12 @@ void parse_pgmopts_or_quit(int argc, char **argv) { } const char *command = argv[1]; - if (!strcmp(command, "edit")) { + if (!strcasecmp(command, "edit")) { pgmopts_rw.pgm = PGM_EDIT; parse_pgmopts_edit(argc, argv); + } else if (!strcasecmp(command, "server")) { + pgmopts_rw.pgm = PGM_SERVER; + parse_pgmopts_server(argc, argv); } else { show_syntax("unsupported command supplied", argc, argv); exit(EXIT_FAILURE); diff --git a/pgmopts.h b/pgmopts.h index cd2a57e..21f047d 100644 --- a/pgmopts.h +++ b/pgmopts.h @@ -38,6 +38,9 @@ struct pgmopts_edit_t { }; struct pgmopts_server_t { + const char *filename; + unsigned int port; + bool answer_udp_queries; unsigned int verbosity; }; diff --git a/server.c b/server.c index 6dff5d3..4c31b63 100644 --- a/server.c +++ b/server.c @@ -37,29 +37,13 @@ #include "log.h" #include "openssl.h" #include "global.h" -#include "keyfile.h" #include "msg.h" #include "util.h" -#include "cmdline.h" #include "server.h" #include "luks.h" +#include "pgmopts.h" -static const struct keyentry_t *server_key; - -static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { - if (max_psk_len < PSK_SIZE_BYTES) { - log_msg(LLVL_FATAL, "Server error: max_psk_len too small."); - return 0; - } - if (strcmp(identity, CLIENT_PSK_IDENTITY)) { - log_msg(LLVL_FATAL, "Server error: client identity '%s' unexpected (expected '%s').", identity, CLIENT_PSK_IDENTITY); - return 0; - } - memcpy(psk, server_key->psk, PSK_SIZE_BYTES); - return PSK_SIZE_BYTES; -} - -static int create_tcp_socket(int port) { +static int create_tcp_server_socket(int port) { int s; struct sockaddr_in addr; @@ -91,6 +75,11 @@ static int create_tcp_socket(int port) { return s; } +#if 0 +static const struct keyentry_t *server_key; + + + /* Wait for the socket to become acceptable or time out after given number of * milliseconds. Return true if acceptable socket is present or false if * timeout occured. */ @@ -175,7 +164,7 @@ static bool all_disks_unlocked(const struct keyentry_t *keyentry) { return true; } -bool tls_server(const struct keyentry_t *key, const struct options_t *options) { +static bool tls_server(const struct keyentry_t *key, const struct options_t *options) { if (all_disks_unlocked(key)) { log_msg(LLVL_INFO, "Starting of server not necessary, all disks already unlocked."); return true; @@ -298,4 +287,122 @@ bool tls_server(const struct keyentry_t *key, const struct options_t *options) { free_generic_tls_context(&gctx); return true; } +#endif +#if 0 +static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { + if (max_psk_len < PSK_SIZE_BYTES) { + log_msg(LLVL_FATAL, "Server error: max_psk_len too small."); + return 0; + } + if (strcmp(identity, CLIENT_PSK_IDENTITY)) { + log_msg(LLVL_FATAL, "Server error: client identity '%s' unexpected (expected '%s').", identity, CLIENT_PSK_IDENTITY); + return 0; + } +// memcpy(psk, server_key->psk, PSK_SIZE_BYTES); + return PSK_SIZE_BYTES; +} +#endif + +static int psk_server_callback(SSL *ssl, const unsigned char *identity, size_t identity_len, SSL_SESSION **sessptr) { + fprintf(stderr, "PSK server SSL %p identity %s len %ld sess %p\n", ssl, identity, identity_len, *sessptr); + SSL_SESSION *sess = SSL_SESSION_new(); + SSL_SESSION_set1_master_key(sess, (const unsigned char*)"\x00\x11\x22", 3); + SSL_SESSION_set_cipher(sess, SSL_get_pending_cipher(ssl)); + //const SSL_CIPHER *cipher = SSL_CIPHER_find(ssl, TLS13_AES_256_GCM_SHA384_BYTES); + //SSL_SESSION_set_cipher(sess, cipher); + SSL_SESSION_set_protocol_version(sess, TLS1_3_VERSION); + *sessptr = sess; + return 1; +} + +struct client_ctx_t { + struct generic_tls_ctx_t *gctx; + int fd; +}; + +static void *client_handler_thread(void *vctx) { + struct client_ctx_t *client = (struct client_ctx_t*)vctx; + + SSL *ssl = SSL_new(client->gctx->ctx); + SSL_set_fd(ssl, client->fd); + + if (SSL_accept(ssl) <= 0) { + ERR_print_errors_fp(stderr); + } else { + log_msg(LLVL_DEBUG, "Client connected, waiting for data..."); + } + + shutdown(client->fd, SHUT_RDWR); + close(client->fd); + free(client); + return NULL; +} + +bool keyserver_start(const struct pgmopts_server_t *opts) { + struct generic_tls_ctx_t gctx; + if (!create_generic_tls_context(&gctx, true)) { + log_msg(LLVL_FATAL, "Failed to create OpenSSL server context."); + return false; + } + + SSL_CTX_set_psk_find_session_callback(gctx.ctx, psk_server_callback); + + int tcp_sock = create_tcp_server_socket(opts->port); + if (tcp_sock == -1) { + log_msg(LLVL_ERROR, "Cannot start server without server socket."); + free_generic_tls_context(&gctx); + return false; + } + + while (true) { + struct sockaddr_in addr; + unsigned int len = sizeof(addr); + int client = accept(tcp_sock, (struct sockaddr*)&addr, &len); + if (client < 0) { + log_libc(LLVL_ERROR, "Unable to accept(2)"); + close(tcp_sock); + free_generic_tls_context(&gctx); + return false; + } + + /* Client has connected, fire up client thread. */ + struct client_ctx_t *client_ctx = calloc(1, sizeof(struct client_ctx_t)); + if (!client_ctx) { + log_libc(LLVL_FATAL, "Unable to malloc(3) client ctx"); + close(tcp_sock); + free_generic_tls_context(&gctx); + return false; + } + client_ctx->gctx = &gctx; + client_ctx->fd = client; + + pthread_t thread; + pthread_attr_t attrs; + if (pthread_attr_init(&attrs)) { + log_libc(LLVL_FATAL, "Unable to pthread_attr_init(3)"); + close(tcp_sock); + free_generic_tls_context(&gctx); + return false; + } + if (pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED)) { + log_libc(LLVL_FATAL, "Unable to pthread_attr_setdetachstate(3)"); + close(tcp_sock); + free_generic_tls_context(&gctx); + return false; + } + if (pthread_create(&thread, &attrs, client_handler_thread, client_ctx)) { + log_libc(LLVL_FATAL, "Unable to pthread_create(3) a client thread"); + close(tcp_sock); + free_generic_tls_context(&gctx); + return false; + + } + + + + } + + free_generic_tls_context(&gctx); + return true; +} diff --git a/server.h b/server.h index 9537289..9bd8805 100644 --- a/server.h +++ b/server.h @@ -24,11 +24,12 @@ #ifndef __SERVER_H__ #define __SERVER_H__ +#include #include "keydb.h" -#include "cmdline.h" +#include "pgmopts.h" /*************** AUTO GENERATED SECTION FOLLOWS ***************/ -bool dtls_server(const struct keyentry_t *key, const struct options_t *options); +bool keyserver_start(const struct pgmopts_server_t *opts); /*************** AUTO GENERATED SECTION ENDS ***************/ #endif