diff --git a/Makefile b/Makefile index ff13371..f0ff81a 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ 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 server.o argparse_server.o thread.o argparse_client.o client.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 thread.o argparse_client.o client.o signals.o parsers: $(PYPGMOPTS) -n edit parsers/parser_edit.py @@ -27,10 +27,10 @@ clean: rm -f $(OBJS) $(OBJS_CFG) luksrku test_s: luksrku - ./luksrku server -vv base + ./luksrku server -vv testdata/server.bin test_c: luksrku - ./luksrku client -vv export 127.0.0.1 + ./luksrku client -vv testdata/client.bin 127.0.0.1 .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/client.c b/client.c index c260f7e..63b7fd9 100644 --- a/client.c +++ b/client.c @@ -41,6 +41,7 @@ #include "client.h" #include "blacklist.h" #include "keydb.h" +#include "uuid.h" #if 0 static const struct keydb_t *client_keydb; @@ -216,11 +217,53 @@ struct keyclient_t { const struct pgmopts_client_t *opts; struct keydb_t *keydb; bool volume_unlocked[MAX_VOLUMES_PER_HOST]; + unsigned char identifier[ASCII_UUID_BUFSIZE]; }; -static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sess) { - fprintf(stderr, "CLIENT CALLBACK\n"); - return 0; +static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sessptr) { + struct keyclient_t *key_client = (struct keyclient_t*)SSL_get_app_data(ssl); + *id = key_client->identifier; + *idlen = ASCII_UUID_CHARACTER_COUNT; + + SSL_SESSION *sess = SSL_SESSION_new(); + if (!sess) { + log_openssl(LLVL_ERROR, "Failed to create SSL_SESSION context for client."); + return 0; + } + + const uint8_t tls13_aes128gcmsha256_id[] = { 0x13, 0x01 }; + const SSL_CIPHER *cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id); + if (!cipher) { + log_openssl(LLVL_ERROR, "Unable to look up SSL_CIPHER for TLSv1.3-PSK"); + return 0; + } + + int return_value = 1; + do { + if (!SSL_SESSION_set1_master_key(sess, key_client->keydb->hosts[0].tls_psk, PSK_SIZE_BYTES)) { + log_openssl(LLVL_ERROR, "Failed to set TLSv1.3-PSK master key."); + return_value = 0; + break; + } + + if (!SSL_SESSION_set_cipher(sess, cipher)) { + log_openssl(LLVL_ERROR, "Failed to set TLSv1.3-PSK cipher."); + return_value = 0; + break; + } + + if (!SSL_SESSION_set_protocol_version(sess, TLS1_3_VERSION)) { + log_openssl(LLVL_ERROR, "Failed to set TLSv1.3-PSK protocol version."); + return_value = 0; + break; + } + } while (false); + + if (return_value) { + *sessptr = sess; + } + + return return_value; } static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) { @@ -237,7 +280,24 @@ static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) { SSL_set_app_data(ssl, keyclient); if (SSL_connect(ssl) == 1) { - fprintf(stderr, "OK\n"); + struct msg_t msg; + while (true) { + int bytes_read = SSL_read(ssl, &msg, sizeof(msg)); + if (bytes_read == 0) { + /* Server closed the connection. */ + break; + } + if (bytes_read != sizeof(msg)) { + log_openssl(LLVL_FATAL, "SSL_read returned %d bytes when we expected to read %d", bytes_read, sizeof(msg)); + break; + } + if (should_log(LLVL_TRACE)) { + char uuid_str[ASCII_UUID_BUFSIZE]; + sprintf_uuid(uuid_str, msg.volume_uuid); + log_msg(LLVL_TRACE, "Received LUKS key to unlock volume with UUID %s", uuid_str); + } + } + OPENSSL_cleanse(&msg, sizeof(msg)); } else { log_openssl(LLVL_FATAL, "SSL_connect failed"); } @@ -292,7 +352,7 @@ static bool contact_keyserver_hostname(struct keyclient_t *keyclient, const char } struct sockaddr_in *sin_address = (struct sockaddr_in*)result->ai_addr; - log_msg(LLVL_DEBUG, "Resolved %s to %d.%d.%d.%d", hostname, PRINTF_FORMAT_IP(sin_address)); + log_msg(LLVL_TRACE, "Resolved %s to %d.%d.%d.%d", hostname, PRINTF_FORMAT_IP(sin_address)); bool success = contact_keyserver_ipv4(keyclient, sin_address, keyclient->opts->port); @@ -334,6 +394,9 @@ bool keyclient_start(const struct pgmopts_client_t *opts) { break; } + /* Transcribe the host UUID to ASCII so we only have to do this once */ + sprintf_uuid((char*)keyclient.identifier, host->host_uuid); + log_msg(LLVL_DEBUG, "Attempting to unlock %d volumes of host \"%s\".", host->volume_count, host->host_name); if (opts->hostname) { if (!contact_keyserver_hostname(&keyclient, opts->hostname)) { diff --git a/keydb.c b/keydb.c index b6b0f3e..6c93930 100644 --- a/keydb.c +++ b/keydb.c @@ -74,8 +74,10 @@ struct keydb_t* keydb_export_public(struct host_entry_t *host) { } void keydb_free(struct keydb_t *keydb) { - OPENSSL_cleanse(keydb, keydb_getsize(keydb)); - free(keydb); + if (keydb) { + OPENSSL_cleanse(keydb, keydb_getsize(keydb)); + free(keydb); + } } static int keydb_get_volume_index_by_name(struct host_entry_t *host, const char *devmapper_name) { diff --git a/log.c b/log.c index 5e9dbc1..d31eed1 100644 --- a/log.c +++ b/log.c @@ -37,6 +37,7 @@ static const char *loglvl_names[] = { [LLVL_WARNING] = "WARNING", [LLVL_INFO] = "INFO", [LLVL_DEBUG] = "DEBUG", + [LLVL_TRACE] = "TRACE", }; void log_setlvl(enum loglvl_t level) { diff --git a/log.h b/log.h index 703dc6b..903097d 100644 --- a/log.h +++ b/log.h @@ -31,7 +31,8 @@ enum loglvl_t { LLVL_ERROR = 1, LLVL_WARNING = 2, LLVL_INFO = 3, - LLVL_DEBUG = 4 + LLVL_DEBUG = 4, + LLVL_TRACE = 5, }; /*************** AUTO GENERATED SECTION FOLLOWS ***************/ diff --git a/server.c b/server.c index 422a337..71ad413 100644 --- a/server.c +++ b/server.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ #include "uuid.h" #include "thread.h" #include "keydb.h" +#include "signals.h" static int create_tcp_server_socket(int port) { int s; @@ -370,6 +372,9 @@ bool keyserver_start(const struct pgmopts_server_t *opts) { struct keydb_t* keydb = NULL; struct generic_tls_ctx_t gctx = { 0 }; do { + /* We ignore SIGPIPE or the server will die when clients disconnect suddenly */ + ignore_signal(SIGPIPE); + /* Load key database first */ keydb = keydb_read(opts->filename); if (!keydb) { diff --git a/signals.c b/signals.c new file mode 100644 index 0000000..143e6de --- /dev/null +++ b/signals.c @@ -0,0 +1,35 @@ +/* + 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 "signals.h" + +bool ignore_signal(int signum) { + struct sigaction action = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + sigemptyset(&action.sa_mask); + return sigaction(signum, &action, NULL) == 0; +} diff --git a/signals.h b/signals.h new file mode 100644 index 0000000..72398b5 --- /dev/null +++ b/signals.h @@ -0,0 +1,33 @@ +/* + 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 __SIGNALS_H__ +#define __SIGNALS_H__ + +#include + +/*************** AUTO GENERATED SECTION FOLLOWS ***************/ +bool ignore_signal(int signum); +/*************** AUTO GENERATED SECTION ENDS ***************/ + +#endif diff --git a/testdata/client.bin b/testdata/client.bin new file mode 100644 index 0000000..a06751b Binary files /dev/null and b/testdata/client.bin differ diff --git a/testdata/server.bin b/testdata/server.bin new file mode 100644 index 0000000..facc703 Binary files /dev/null and b/testdata/server.bin differ