diff --git a/Makefile b/Makefile index 72b34bd..b5a6c1a 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ INSTALL_PREFIX := /usr/local/ CFLAGS := -Wall -Wextra -Wshadow -Wswitch -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Werror=implicit-function-declaration -Werror=format -Wno-unused-parameter CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"' CFLAGS += `pkg-config --cflags openssl` -#CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak +CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak PYPGMOPTS := ../Python/pypgmopts/pypgmopts LDFLAGS := `pkg-config --libs openssl` @@ -33,6 +33,7 @@ OBJS := \ udp.o \ util.o \ uuid.o \ + vaulted_keydb.o \ vault.o parsers: diff --git a/editor.c b/editor.c index 81a47eb..dfda178 100644 --- a/editor.c +++ b/editor.c @@ -32,6 +32,7 @@ #include "keydb.h" #include "uuid.h" #include "log.h" +#include "vaulted_keydb.h" #define MAX_COMMAND_ALIAS_COUNT 2 @@ -72,6 +73,7 @@ static enum cmd_returncode_t cmd_open(struct editor_context_t *ctx, const char * static enum cmd_returncode_t cmd_save(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params); static enum cmd_returncode_t cmd_export(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params); #ifdef DEBUG +static enum cmd_returncode_t cmd_test(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params); static enum cmd_returncode_t cmd_rawdump(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params); #endif @@ -172,6 +174,13 @@ static const struct editor_command_t commands[] = { .description = "Export a host database file for a specific host", }, #ifdef DEBUG + { + .cmdnames = { "test", "t" }, + .callback = cmd_test, + .min_params = 1, + .max_params = 1, + .description = "Test different aspects of luksrku. Used only for debugging.", + }, { .cmdnames = { "rawdump", "raw" }, .callback = cmd_rawdump, @@ -431,6 +440,33 @@ static enum cmd_returncode_t cmd_export(struct editor_context_t *ctx, const char #ifdef DEBUG +static enum cmd_returncode_t cmd_test(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) { + const char *cmd = params[0]; + if (!strcmp(cmd, "vault")) { + if (!ctx->keydb) { + fprintf(stderr, "No keydb.\n"); + return COMMAND_FAILURE; + } + struct vaulted_keydb_t *vkdb = vaulted_keydb_new(ctx->keydb); + fprintf(stderr, "Vault created at %p.\n", vkdb); + fprintf(stderr, "TLS-PSK vault %u bytes:\n", vkdb->tls_psk_vault->data_length); + dump_hex_long(stderr, vkdb->tls_psk_vault->data, vkdb->tls_psk_vault->data_length); + fprintf(stderr, "LUKS vault %u bytes:\n", vkdb->luks_passphrase_vault->data_length); + dump_hex_long(stderr, vkdb->luks_passphrase_vault->data, vkdb->luks_passphrase_vault->data_length); + + fprintf(stderr, "~~~~~~~~~~~~~~~~ decrypted TLS-PSK ~~~~~~~~~~~~~~~~\n"); + vault_open(vkdb->tls_psk_vault); + dump_hex_long(stderr, vkdb->tls_psk_vault->data, vkdb->tls_psk_vault->data_length); + fprintf(stderr, "~~~~~~~~~~~~~~~~ decrypted LUKS ~~~~~~~~~~~~~~~~\n"); + vault_open(vkdb->luks_passphrase_vault); + dump_hex_long(stderr, vkdb->luks_passphrase_vault->data, vkdb->luks_passphrase_vault->data_length); + vaulted_keydb_free(vkdb); + return COMMAND_SUCCESS; + } + fprintf(stderr, "Test accepts one of these commands: vault\n"); + return COMMAND_FAILURE; +} + static enum cmd_returncode_t cmd_rawdump(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) { if (!ctx->keydb) { return COMMAND_SUCCESS; diff --git a/vault.c b/vault.c index ed32443..8e3afa7 100644 --- a/vault.c +++ b/vault.c @@ -257,6 +257,9 @@ bool vault_close(struct vault_t *vault) { void vault_free(struct vault_t *vault) { + if (!vault) { + return; + } vault_destroy_content(vault); free(vault->data); free(vault->key); diff --git a/vaulted_keydb.c b/vaulted_keydb.c new file mode 100644 index 0000000..a84e492 --- /dev/null +++ b/vaulted_keydb.c @@ -0,0 +1,117 @@ +/* + 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 +*/ + +#include +#include +#include +#include "vaulted_keydb.h" +#include "log.h" + +static struct tls_psk_vault_entry_t *vaulted_keydb_get_tls_psk_for_hostindex(struct vaulted_keydb_t *vkeydb, unsigned int host_index) { + return ((struct tls_psk_vault_entry_t*)vkeydb->tls_psk_vault->data) + host_index; +} + +static struct luks_passphrase_vault_entry_t *vaulted_keydb_get_luks_passphrase_for_hostindex(struct vaulted_keydb_t *vkeydb, unsigned int host_index) { + return ((struct luks_passphrase_vault_entry_t*)vkeydb->luks_passphrase_vault->data) + host_index; +} + +static void copy_data_into_vault(struct vaulted_keydb_t *dest, struct keydb_t *src) { + for (unsigned int i = 0; i < src->host_count; i++) { + struct host_entry_t *host = &src->hosts[i]; + + /* Copy over TLS-PSK and remove original */ + struct tls_psk_vault_entry_t *dest_tls_psk = vaulted_keydb_get_tls_psk_for_hostindex(dest, i); + memcpy(&dest_tls_psk->tls_psk, host->tls_psk, PSK_SIZE_BYTES); + OPENSSL_cleanse(host->tls_psk, PSK_SIZE_BYTES); + + /* Copy over all LUKS keys and remove originals */ + struct luks_passphrase_vault_entry_t *dest_luks_passphrase = vaulted_keydb_get_luks_passphrase_for_hostindex(dest, i); + for (unsigned int j = 0; j < host->volume_count; j++) { + struct volume_entry_t *volume = &host->volumes[j]; + memcpy(&dest_luks_passphrase->volumes[j].luks_passphrase_raw, volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES); + OPENSSL_cleanse(volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES); + } + } +} + +static void erase_key_data_from_keydb(struct keydb_t *keydb) { + for (unsigned int i = 0; i < keydb->host_count; i++) { + struct host_entry_t *host = &keydb->hosts[i]; + OPENSSL_cleanse(host->tls_psk, PSK_SIZE_BYTES); + for (unsigned int j = 0; j < host->volume_count; j++) { + struct volume_entry_t *volume = &host->volumes[j]; + OPENSSL_cleanse(volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES); + } + } +} + +struct vaulted_keydb_t *vaulted_keydb_new(struct keydb_t *keydb) { + struct vaulted_keydb_t *vaulted_keydb = calloc(1, sizeof(struct vaulted_keydb_t)); + if (!vaulted_keydb) { + log_msg(LLVL_FATAL, "Unable to calloc(3) vaulted keydb"); + return NULL; + } + + vaulted_keydb->keydb = keydb; + + vaulted_keydb->tls_psk_vault = vault_init(sizeof(struct tls_psk_vault_entry_t) * keydb->host_count, 0.1); + if (!vaulted_keydb->tls_psk_vault) { + log_msg(LLVL_FATAL, "Unable to create TLS-PSK vault"); + vaulted_keydb_free(vaulted_keydb); + return NULL; + } + + vaulted_keydb->luks_passphrase_vault = vault_init(sizeof(struct luks_passphrase_vault_entry_t) * keydb->host_count, 0.1); + if (!vaulted_keydb->luks_passphrase_vault) { + log_msg(LLVL_FATAL, "Unable to create LUKS passphrase vault"); + vaulted_keydb_free(vaulted_keydb); + return NULL; + } + + /* Now copy over data from the original KeyDB */ + copy_data_into_vault(vaulted_keydb, keydb); + + /* Then erase original key data */ + erase_key_data_from_keydb(keydb); + + /* Finally, close the vaults */ + if (!vault_close(vaulted_keydb->tls_psk_vault)) { + log_msg(LLVL_FATAL, "Failed to close TLS-PSK vault"); + vaulted_keydb_free(vaulted_keydb); + return NULL; + } + + if (!vault_close(vaulted_keydb->luks_passphrase_vault)) { + log_msg(LLVL_FATAL, "Failed to close LUKS passhrase vault"); + vaulted_keydb_free(vaulted_keydb); + return NULL; + } + + return vaulted_keydb; +} + +void vaulted_keydb_free(struct vaulted_keydb_t *vaulted_keydb) { + vault_free(vaulted_keydb->luks_passphrase_vault); + vault_free(vaulted_keydb->tls_psk_vault); + free(vaulted_keydb); +} diff --git a/vaulted_keydb.h b/vaulted_keydb.h new file mode 100644 index 0000000..1751e6b --- /dev/null +++ b/vaulted_keydb.h @@ -0,0 +1,51 @@ +/* + 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 __VAULTED_KEYDB_H__ +#define __VAULTED_KEYDB_H__ + +#include "keydb.h" +#include "vault.h" + +struct tls_psk_vault_entry_t { + uint8_t tls_psk[PSK_SIZE_BYTES]; +}; + +struct luks_passphrase_vault_entry_t { + struct { + uint8_t luks_passphrase_raw[LUKS_PASSPHRASE_RAW_SIZE_BYTES]; + } volumes[MAX_VOLUMES_PER_HOST]; +}; + +struct vaulted_keydb_t { + struct keydb_t *keydb; + struct vault_t *tls_psk_vault; + struct vault_t *luks_passphrase_vault; +}; + +/*************** AUTO GENERATED SECTION FOLLOWS ***************/ +struct vaulted_keydb_t *vaulted_keydb_new(struct keydb_t *keydb); +void vaulted_keydb_free(struct vaulted_keydb_t *vaulted_keydb); +/*************** AUTO GENERATED SECTION ENDS ***************/ + +#endif