From 0cb0e5d4707e09c3d140ca6e41a35e9fcb6c8509 Mon Sep 17 00:00:00 2001 From: Johannes Bauer Date: Sun, 20 Oct 2019 21:09:41 +0200 Subject: [PATCH] Further work in keydb Work in transcribing the binary LUKS PSK to ASCII. Still buggy, had an error in thinking (it's not 4 bytes transcribed to 3, but 3 to 4 of course). Needs fixing. --- editor.c | 40 +++++++++++++++++++++++++++++++--- keydb.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- keydb.h | 8 ++++++- util.c | 33 ++++++++++++++++++++++++++++ util.h | 2 ++ 5 files changed, 142 insertions(+), 6 deletions(-) diff --git a/editor.c b/editor.c index 727cc5c..988a730 100644 --- a/editor.c +++ b/editor.c @@ -110,7 +110,7 @@ static const struct editor_command_t commands[] = { .param_names = "[hostname] [volumename]", .min_params = 2, .max_params = 2, - .description = "Re-keys a volume of a given hostname", + .description = "Re-keys the LUKS passphrase of a volume of a given hostname", }, { .cmdnames = { "showkey_volume" }, @@ -118,7 +118,7 @@ static const struct editor_command_t commands[] = { .param_names = "[hostname] [volumename]", .min_params = 2, .max_params = 2, - .description = "Shows the key of a volume of a hostname", + .description = "Shows the LUKS passphrase of a volume of a hostname", }, { .cmdnames = { "open", "load" }, @@ -200,7 +200,27 @@ static enum cmd_returncode_t cmd_add_host(struct editor_context_t *ctx, const ch } static enum cmd_returncode_t cmd_add_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) { - return COMMAND_SUCCESS; + if (!ctx->keydb) { + fprintf(stderr, "No key database loaded.\n"); + return COMMAND_FAILURE; + } + + const char *host_name = params[0]; + struct host_entry_t *host = keydb_get_host_by_name(ctx->keydb, host_name); + if (!host) { + fprintf(stderr, "No such host: %s\n", host_name); + return COMMAND_FAILURE; + } + + const char *volume_name = params[1]; + const char *volume_uuid_str = params[2]; + if (!is_valid_uuid(volume_uuid_str)) { + fprintf(stderr, "Not a valid UUID: %s\n", volume_uuid_str); + return COMMAND_FAILURE; + } + uint8_t volume_uuid[16]; + parse_uuid(volume_uuid, volume_uuid_str); + return keydb_add_volume(host, volume_name, volume_uuid) ? COMMAND_SUCCESS : COMMAND_FAILURE; } static enum cmd_returncode_t cmd_rekey_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) { @@ -208,6 +228,20 @@ static enum cmd_returncode_t cmd_rekey_volume(struct editor_context_t *ctx, cons } static enum cmd_returncode_t cmd_showkey_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) { + const char *host_name = params[0]; + struct host_entry_t *host = keydb_get_host_by_name(ctx->keydb, host_name); + if (!host) { + fprintf(stderr, "No such host: %s\n", host_name); + return COMMAND_FAILURE; + } + + const char *volume_name = params[1]; + struct volume_entry_t *volume = keydb_get_volume_by_name(host, volume_name); + if (!volume) { + fprintf(stderr, "No such volume: %s\n", volume_name); + return COMMAND_FAILURE; + } + return COMMAND_SUCCESS; } diff --git a/keydb.c b/keydb.c index aed1306..63a4a9b 100644 --- a/keydb.c +++ b/keydb.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -52,8 +53,13 @@ void keydb_free(struct keydb_t *keydb) { free(keydb); } -bool keydb_add_host(struct keydb_t **keydb, const char *hostname) { +bool keydb_add_host(struct keydb_t **keydb, const char *host_name) { struct keydb_t *old_keydb = *keydb; + if (keydb_get_host_by_name(old_keydb, host_name)) { + log_msg(LLVL_ERROR, "Host name \"%s\" already present in key database.", host_name); + return false; + } + struct keydb_t *new_keydb = realloc(old_keydb, keydb_getsize_hostcount(old_keydb->host_count + 1)); if (!new_keydb) { return false; @@ -66,7 +72,7 @@ bool keydb_add_host(struct keydb_t **keydb, const char *hostname) { /* We keep the reallocation but do not increase the host count */ return false; } - strncpy(host->host_name, hostname, sizeof(host->host_name) - 1); + strncpy(host->host_name, host_name, sizeof(host->host_name) - 1); if (!buffer_randomize(host->tls_psk, sizeof(host->tls_psk))) { /* We keep the reallocation but do not increase the host count */ return false; @@ -76,6 +82,61 @@ bool keydb_add_host(struct keydb_t **keydb, const char *hostname) { return true; } +bool keydb_add_volume(struct host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]) { + if (host->volume_count == MAX_VOLUMES_PER_HOST) { + log_msg(LLVL_ERROR, "Host \"%s\" already has maximum number of volumes (%d).", host->host_name, MAX_VOLUMES_PER_HOST); + return false; + } + if (keydb_get_volume_by_name(host, devmapper_name)) { + log_msg(LLVL_ERROR, "Volume name \"%s\" already present for host \"%s\" entry.", devmapper_name, host->host_name); + return false; + } + + struct volume_entry_t *volume = &host->volumes[host->volume_count]; + memcpy(volume->volume_uuid, volume_uuid, 16); + strncpy(volume->devmapper_name, devmapper_name, sizeof(volume->devmapper_name) - 1); + if (!buffer_randomize(volume->luks_passphrase, sizeof(volume->luks_passphrase))) { + log_msg(LLVL_ERROR, "Failed to produce %d bytes of entropy for LUKS passphrase.", sizeof(volume->luks_passphrase)); + return false; + } + host->volume_count++; + return true; +} + +int keydb_get_volume_index_by_name(struct host_entry_t *host, const char *devmapper_name) { + for (unsigned int i = 0; i < host->volume_count; i++) { + struct volume_entry_t *volume = &host->volumes[i]; + if (!strcasecmp(volume->devmapper_name, devmapper_name)) { + return i; + } + } + return -1; +} + +struct volume_entry_t *keydb_get_volume_by_name(struct host_entry_t *host, const char *devmapper_name) { + const int index = keydb_get_volume_index_by_name(host, devmapper_name); + return (index >= 0) ? &host->volumes[index] : NULL; +} + +int keydb_get_host_index_by_name(struct keydb_t *keydb, const char *host_name) { + for (unsigned int i = 0; i < keydb->host_count; i++) { + struct host_entry_t *host = &keydb->hosts[i]; + if (!strcasecmp(host->host_name, host_name)) { + return i; + } + } + return -1; +} + +bool keydb_get_volume_luks_passphrase(const struct volume_entry_t *volume, char *dest) { + return ascii_encode(dest, volume->luks_passphrase, sizeof(volume->luks_passphrase)); +} + +struct host_entry_t *keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name) { + const int index = keydb_get_host_index_by_name(keydb, host_name); + return (index >= 0) ? &keydb->hosts[index] : NULL; +} + bool keydb_write(const struct keydb_t *keydb, const char *filename, const char *passphrase) { enum kdf_t kdf; if ((!passphrase) || (strlen(passphrase) == 0)) { diff --git a/keydb.h b/keydb.h index 6d742e9..249da6b 100644 --- a/keydb.h +++ b/keydb.h @@ -56,7 +56,13 @@ struct keydb_t { /*************** AUTO GENERATED SECTION FOLLOWS ***************/ struct keydb_t* keydb_new(void); void keydb_free(struct keydb_t *keydb); -bool keydb_add_host(struct keydb_t **keydb, const char *hostname); +bool keydb_add_host(struct keydb_t **keydb, const char *host_name); +bool keydb_add_volume(struct host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]); +int keydb_get_volume_index_by_name(struct host_entry_t *host, const char *devmapper_name); +struct volume_entry_t *keydb_get_volume_by_name(struct host_entry_t *host, const char *devmapper_name); +int keydb_get_host_index_by_name(struct keydb_t *keydb, const char *host_name); +bool keydb_get_volume_luks_passphrase(const struct volume_entry_t *volume, char *dest); +struct host_entry_t *keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name); bool keydb_write(const struct keydb_t *keydb, const char *filename, const char *passphrase); struct keydb_t* keydb_read(const char *filename); /*************** AUTO GENERATED SECTION ENDS ***************/ diff --git a/util.c b/util.c index 1fa47b7..3327930 100644 --- a/util.c +++ b/util.c @@ -141,3 +141,36 @@ bool buffer_randomize(uint8_t *buffer, unsigned int length) { fclose(f); return true; } + +bool array_remove(void *base, unsigned int element_length, unsigned int element_count, unsigned int remove_element_index) { + if (remove_element_index >= element_count) { + return false; + } + uint8_t *bytebase = (uint8_t*)base; + const unsigned int destination_offset = remove_element_index * element_length; + const unsigned int source_offset = (remove_element_index + 1) * element_length; + const unsigned int copy_length = ((element_count - 1) - remove_element_index) * element_length; + if (copy_length) { + memcpy(bytebase + destination_offset, bytebase + source_offset, copy_length); + } + return true; +} + +bool ascii_encode(char *dest, unsigned int dest_buffer_size, const uint8_t *source_data, unsigned int source_data_length) { + + const char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+"; + if ((source_data_length % 4) != 0) { + log_libc(LLVL_FATAL, "Can only encode binary data of which length is divisible by four, %d is not.", source_data_length); + return false; + } + const unsigned int require_dest_size = source_data_length / 4 + + for (unsigned int i = 0; i < source_data_length; i += 3) { + uint32_t word = (source_data[i + 0] << 0) | (source_data[i + 1] << 8) | (source_data[i + 2] << 16); + for (unsigned int shift = 0; shift < 24; shift += 6) { + *dest++ = alphabet[(word >> shift) & 0x3f]; + } + } + *dest = 0; + return true; +} diff --git a/util.h b/util.h index a7b01e2..078d287 100644 --- a/util.h +++ b/util.h @@ -38,6 +38,8 @@ bool is_hex(const char *str, int length); int parse_hexstr(const char *hexstr, uint8_t *data, int maxlen); bool truncate_crlf(char *string); bool buffer_randomize(uint8_t *buffer, unsigned int length); +bool array_remove(void *base, unsigned int element_length, unsigned int element_count, unsigned int remove_element_index); +bool ascii_encode(char *dest, const uint8_t *source_data, unsigned int source_data_length); /*************** AUTO GENERATED SECTION ENDS ***************/ #endif