Compare commits

..

12 Commits

Author SHA1 Message Date
Johannes Bauer
204f85c93f Release v0.04
Have been using this for long enough to consider it stable, releasing it
as v0.04.
2021-09-17 21:50:53 +02:00
Johannes Bauer
78a8cd70c2 Disabled command line default timeout
The command line default timeout of 60 seconds always took precedence,
we removed it. Also added a debug statement that lets the user know how
long they will have to wait.
2021-06-27 13:29:43 +02:00
Johannes Bauer
46b2cdb184 Remove duplicate newline
There's accidently two newlines in the editor, removed.
2021-06-27 13:06:23 +02:00
Johannes Bauer
a6db05b4d0 Allow editing of timeout parameter
Implemented the edit command that allows changing the timeout parameter.
2021-06-27 13:00:06 +02:00
Johannes Bauer
a764cc22e2 Print timeout parameter of database
Changed the list command to show the current timeout value.
2021-06-27 12:54:28 +02:00
Johannes Bauer
323db6d08d Default timeout parameter added
When we're modifying the binary format, we can introduce host-dependent
timeouts as well.
2021-06-27 12:51:51 +02:00
Johannes Bauer
37b239b179 Fixed issue with member access
This is kind of hacky, but it avoids the segfault at runtime. So,
preferrable. If we ever have more options, we need to properly generate
the argv[] array.
2021-06-27 12:32:44 +02:00
Johannes Bauer
b0fc16bfc7 Consistent naming and implemented flag honoring
Name the flag exactly as it's used by LUKS everywhere: allow_discards
(we had in some places "discard", "allow_discard"). Implement actually
honoring that flag if it's set. Untested code.
2021-06-27 09:47:59 +02:00
Johannes Bauer
cd38193993 Allow editing of volume flags
We can now set the "discard" flag of volumes, but it's not yet honored.
2021-06-27 09:42:04 +02:00
Johannes Bauer
bd5caae1ee Introduce new host_flags field
While we're at it with migration, might as well add a host_flags field
so that if we have host-specific configuration flags we want to add
later on, we only have to do a migration once.
2021-06-27 09:17:05 +02:00
Johannes Bauer
af29d9cbf8 Preliminary file migration
Pretty raw and untested code which migrates data from v2 to v3,
introducing a new field in the process. This field is neither editable
as of now nor is it honored if it were set.
2021-06-27 00:28:00 +02:00
Johannes Bauer
b0909557ad Refactoring of version code
We want to introduce a new feature (volumes with discard support) which
will cause file incompatibility.  This means we need to prepare data
migration code. This prepares that change.
2021-06-26 23:34:26 +02:00
17 changed files with 383 additions and 155 deletions

View File

@ -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`

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:16
* Generated at: 2021-06-27 13:24:40
*/
#include <stdint.h>
@ -154,21 +154,18 @@ void argparse_client_show_syntax(void) {
fprintf(stderr, "Connects to a luksrku key server and unlocks local LUKS volumes.\n");
fprintf(stderr, "\n");
fprintf(stderr, "positional arguments:\n");
fprintf(stderr, " filename Exported database file to load TLS-PSKs and list of\n");
fprintf(stderr, " disks from.\n");
fprintf(stderr, " hostname When hostname is given, auto-searching for suitable\n");
fprintf(stderr, " servers is disabled and only a connection to the given\n");
fprintf(stderr, " hostname is attempted.\n");
fprintf(stderr, " filename Exported database file to load TLS-PSKs and list of disks from.\n");
fprintf(stderr, " hostname When hostname is given, auto-searching for suitable servers is disabled and\n");
fprintf(stderr, " only a connection to the given hostname is attempted.\n");
fprintf(stderr, "\n");
fprintf(stderr, "optional arguments:\n");
fprintf(stderr, " -t secs, --timeout secs\n");
fprintf(stderr, " When searching for a keyserver and not all volumes can\n");
fprintf(stderr, " be unlocked, abort after this period of time, given in\n");
fprintf(stderr, " seconds. Defaults to 60 seconds.\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, " --no-luks Do not call LUKS/cryptsetup. Useful for testing\n");
fprintf(stderr, " unlocking procedure.\n");
fprintf(stderr, " When searching for a keyserver and not all volumes can be unlocked, abort\n");
fprintf(stderr, " after this period of time, given in seconds. Defaults to infinity. This\n");
fprintf(stderr, " argument can be specified as a host-based configuration parameter as well;\n");
fprintf(stderr, " the command-line argument always takes precedence.\n");
fprintf(stderr, " -p port, --port port Port that is used for both UDP and TCP communication. Defaults to 23170.\n");
fprintf(stderr, " --no-luks Do not call LUKS/cryptsetup. Useful for testing unlocking procedure.\n");
fprintf(stderr, " -v, --verbose Increase verbosity. Can be specified multiple times.\n");
}

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:16
* Generated at: 2021-06-27 13:24:40
*/
#ifndef __ARGPARSE_CLIENT_H__
@ -13,7 +13,7 @@
#include <stdbool.h>
#define ARGPARSE_CLIENT_DEFAULT_TIMEOUT 60
#define ARGPARSE_CLIENT_DEFAULT_TIMEOUT 0
#define ARGPARSE_CLIENT_DEFAULT_PORT 23170
#define ARGPARSE_CLIENT_DEFAULT_VERBOSE 0

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:15
* Generated at: 2021-06-27 13:24:40
*/
#include <stdint.h>

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:15
* Generated at: 2021-06-27 13:24:40
*/
#ifndef __ARGPARSE_EDIT_H__

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:15
* Generated at: 2021-06-27 13:24:40
*/
#include <stdint.h>
@ -133,10 +133,9 @@ void argparse_server_show_syntax(void) {
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, " -p port, --port port Port that is used for both UDP and TCP communication. Defaults to 23170.\n");
fprintf(stderr, " -s, --silent Do not answer UDP queries for clients trying to find a key server, only\n");
fprintf(stderr, " serve key database using TCP.\n");
fprintf(stderr, " -v, --verbose Increase verbosity. Can be specified multiple times.\n");
}

View File

@ -5,7 +5,7 @@
*
* Do not edit it by hand, your changes will be overwritten.
*
* Generated at: 2019-10-25 20:39:15
* Generated at: 2021-06-27 13:24:40
*/
#ifndef __ARGPARSE_SERVER_H__

View File

@ -47,7 +47,7 @@
struct keyclient_t {
const struct pgmopts_client_t *opts;
struct keydb_t *keydb;
keydb_t *keydb;
bool volume_unlocked[MAX_VOLUMES_PER_HOST];
unsigned char identifier[ASCII_UUID_BUFSIZE];
double broadcast_start_time;
@ -61,11 +61,12 @@ static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char *
return openssl_tls13_psk_establish_session(ssl, key_client->keydb->hosts[0].tls_psk, PSK_SIZE_BYTES, EVP_sha256(), sessptr);
}
static bool unlock_luks_volume(const struct volume_entry_t *volume, const struct msg_t *unlock_msg) {
static bool unlock_luks_volume(const volume_entry_t *volume, const struct msg_t *unlock_msg) {
bool success = true;
char luks_passphrase[LUKS_PASSPHRASE_TEXT_SIZE_BYTES];
if (ascii_encode(luks_passphrase, sizeof(luks_passphrase), unlock_msg->luks_passphrase_raw, sizeof(unlock_msg->luks_passphrase_raw))) {
success = open_luks_device(volume->volume_uuid, volume->devmapper_name, luks_passphrase, strlen(luks_passphrase));
bool allow_discards = volume->volume_flags & VOLUME_FLAG_ALLOW_DISCARDS;
success = open_luks_device(volume->volume_uuid, volume->devmapper_name, luks_passphrase, strlen(luks_passphrase), allow_discards);
} else {
log_msg(LLVL_FATAL, "Failed to transcribe raw LUKS passphrase to text form.");
success = false;
@ -75,8 +76,8 @@ static bool unlock_luks_volume(const struct volume_entry_t *volume, const struct
}
static bool attempt_unlock_luks_volume(struct keyclient_t *keyclient, const struct msg_t *unlock_msg) {
const struct host_entry_t *host = &keyclient->keydb->hosts[0];
const struct volume_entry_t* volume = keydb_get_volume_by_uuid(host, unlock_msg->volume_uuid);
const host_entry_t *host = &keyclient->keydb->hosts[0];
const volume_entry_t* volume = keydb_get_volume_by_uuid(host, unlock_msg->volume_uuid);
char volume_uuid_str[ASCII_UUID_BUFSIZE];
sprintf_uuid(volume_uuid_str, unlock_msg->volume_uuid);
if (!volume) {
@ -224,16 +225,29 @@ static bool all_volumes_unlocked(struct keyclient_t *keyclient) {
return locked_volume_count(keyclient) == 0;
}
static unsigned int determine_timeout(struct keyclient_t *keyclient) {
unsigned int client_timeout_secs = 0;
if (keyclient->opts->timeout_seconds) {
/* Command line always has precedence */
client_timeout_secs = keyclient->opts->timeout_seconds;
} else {
/* Alternatively, take the one in the configuration file */
client_timeout_secs = keyclient->keydb->hosts[0].client_default_timeout_secs;
}
return client_timeout_secs;
}
static bool abort_searching_for_keyserver(struct keyclient_t *keyclient) {
if (all_volumes_unlocked(keyclient)) {
log_msg(LLVL_DEBUG, "All volumes unlocked successfully.");
return true;
}
if (keyclient->opts->timeout_seconds) {
unsigned int client_timeout_secs = determine_timeout(keyclient);
if (client_timeout_secs) {
double time_passed = now() - keyclient->broadcast_start_time;
if (time_passed >= keyclient->opts->timeout_seconds) {
log_msg(LLVL_WARNING, "Could not unlock all volumes after %u seconds, giving up. %d volumes still locked.", keyclient->opts->timeout_seconds, locked_volume_count(keyclient));
if (time_passed >= client_timeout_secs) {
log_msg(LLVL_WARNING, "Could not unlock all volumes after %u seconds, giving up. %d volumes still locked.", client_timeout_secs, locked_volume_count(keyclient));
return true;
}
}
@ -242,11 +256,21 @@ static bool abort_searching_for_keyserver(struct keyclient_t *keyclient) {
}
static bool broadcast_for_keyserver(struct keyclient_t *keyclient) {
{
unsigned int client_timeout_secs = determine_timeout(keyclient);
if (client_timeout_secs) {
log_msg(LLVL_DEBUG, "Searching luksrku keyserver, will give up after %u seconds", client_timeout_secs);
} else {
log_msg(LLVL_DEBUG, "Searching luksrku keyserver, will not give up until all volumes unlocked");
}
}
int sd = create_udp_socket(0, true, 1000);
if (sd == -1) {
return false;
}
keyclient->broadcast_start_time = now();
struct udp_query_t query;
memcpy(query.magic, UDP_MESSAGE_MAGIC, sizeof(query.magic));
@ -307,7 +331,7 @@ bool keyclient_start(const struct pgmopts_client_t *opts) {
break;
}
struct host_entry_t *host = &keyclient.keydb->hosts[0];
host_entry_t *host = &keyclient.keydb->hosts[0];
if (host->volume_count == 0) {
log_msg(LLVL_FATAL, "No volumes found in exported database %s.", opts->filename);
success = false;

131
editor.c
View File

@ -45,7 +45,7 @@ enum cmd_returncode_t {
struct editor_context_t {
bool running;
struct keydb_t *keydb;
keydb_t *keydb;
char filename[MAX_FILENAME_LENGTH];
char passphrase[MAX_PASSPHRASE_LENGTH];
};
@ -65,10 +65,12 @@ static enum cmd_returncode_t cmd_list(struct editor_context_t *ctx, const char *
static enum cmd_returncode_t cmd_add_host(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_del_host(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_rekey_host(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_host_param(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_add_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_del_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_rekey_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_showkey_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_flag_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
static enum cmd_returncode_t cmd_open(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params);
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);
@ -117,6 +119,14 @@ static const struct editor_command_t commands[] = {
.max_params = 1,
.description = "Re-keys the TLS PSK of a given host",
},
{
.cmdnames = { "host_param" },
.callback = cmd_host_param,
.param_names = "[hostname] timeout [value]",
.min_params = 3,
.max_params = 3,
.description = "Set a parameter of a host (currently only timeout supported)",
},
{
.cmdnames = { "add_volume" },
.callback = cmd_add_volume,
@ -149,6 +159,14 @@ static const struct editor_command_t commands[] = {
.max_params = 2,
.description = "Shows the LUKS passphrase of a volume of a hostname",
},
{
.cmdnames = { "flag_volume" },
.callback = cmd_flag_volume,
.param_names = "[hostname] [devmappername] [(+-)(allow_discards)]",
.min_params = 3,
.max_params = 3,
.description = "Edits the flags of a volume",
},
{
.cmdnames = { "open", "load" },
.callback = cmd_open,
@ -227,16 +245,30 @@ static enum cmd_returncode_t cmd_list(struct editor_context_t *ctx, const char *
printf("No key database loaded.\n");
return COMMAND_FAILURE;
}
printf("Keydb version %d, %s database, %d hosts.\n", ctx->keydb->keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count);
printf("Keydb version %d, %s database, %d hosts.\n", ctx->keydb->common.keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count);
for (unsigned int i = 0; i < ctx->keydb->host_count; i++) {
const struct host_entry_t *host = &ctx->keydb->hosts[i];
const host_entry_t *host = &ctx->keydb->hosts[i];
char uuid[48];
sprintf_uuid(uuid, host->host_uuid);
printf(" Host %d: \"%s\" UUID %s -- %d volumes:\n", i + 1, host->host_name, uuid, host->volume_count);
printf(" Host %d: \"%s\" UUID %s -- %d volumes, ", i + 1, host->host_name, uuid, host->volume_count);
if (!host->client_default_timeout_secs) {
printf("no default timeout");
} else {
printf("default timeout %d secs", host->client_default_timeout_secs);
}
printf(":\n");
for (unsigned int j = 0; j < host->volume_count; j++) {
const struct volume_entry_t *volume = &host->volumes[j];
const volume_entry_t *volume = &host->volumes[j];
sprintf_uuid(uuid, volume->volume_uuid);
printf(" Volume %d: \"%s\" UUID %s\n", j + 1, volume->devmapper_name, uuid);
printf(" Volume %d: \"%s\" UUID %s ", j + 1, volume->devmapper_name, uuid);
if (volume->volume_flags == 0) {
printf("defaults");
} else {
if (volume->volume_flags & VOLUME_FLAG_ALLOW_DISCARDS) {
printf("allow_discards ");
}
}
printf("\n");
}
}
return COMMAND_SUCCESS;
@ -265,12 +297,12 @@ static enum cmd_returncode_t cmd_del_host(struct editor_context_t *ctx, const ch
return success ? COMMAND_SUCCESS : COMMAND_FAILURE;
}
static struct host_entry_t* cmd_gethost(struct editor_context_t *ctx, const char *host_name) {
static host_entry_t* cmd_gethost(struct editor_context_t *ctx, const char *host_name) {
if (!ctx->keydb) {
fprintf(stderr, "No key database loaded.\n");
return NULL;
}
struct host_entry_t *host = keydb_get_host_by_name(ctx->keydb, host_name);
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 NULL;
@ -278,13 +310,13 @@ static struct host_entry_t* cmd_gethost(struct editor_context_t *ctx, const char
return host;
}
static struct volume_entry_t* cmd_getvolume(struct editor_context_t *ctx, const char *host_name, const char *devmapper_name) {
struct host_entry_t *host = cmd_gethost(ctx, host_name);
static volume_entry_t* cmd_getvolume(struct editor_context_t *ctx, const char *host_name, const char *devmapper_name) {
host_entry_t *host = cmd_gethost(ctx, host_name);
if (!host) {
return NULL;
}
struct volume_entry_t *volume = keydb_get_volume_by_name(host, devmapper_name);
volume_entry_t *volume = keydb_get_volume_by_name(host, devmapper_name);
if (!volume) {
fprintf(stderr, "No such volume \"%s\" for host \"%s\"\n", devmapper_name, host_name);
return NULL;
@ -294,11 +326,30 @@ static struct volume_entry_t* cmd_getvolume(struct editor_context_t *ctx, const
static enum cmd_returncode_t cmd_rekey_host(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 = cmd_gethost(ctx, host_name);
host_entry_t *host = cmd_gethost(ctx, host_name);
return host && keydb_rekey_host(host) ? COMMAND_SUCCESS : COMMAND_FAILURE;
}
static enum cmd_returncode_t cmd_do_showkey_volume(struct volume_entry_t *volume) {
static enum cmd_returncode_t cmd_host_param(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) {
const char *host_name = params[0];
const char *param = params[1];
const char *value = params[2];
host_entry_t *host = cmd_gethost(ctx, host_name);
if (!host) {
return COMMAND_FAILURE;
}
if (!strcasecmp(param, "timeout")) {
host->client_default_timeout_secs = atoi(value);
} else {
fprintf(stderr, "Invalid parameter: %s\n", param);
return COMMAND_FAILURE;
}
return COMMAND_SUCCESS;
}
static enum cmd_returncode_t cmd_do_showkey_volume(volume_entry_t *volume) {
char luks_passphrase[LUKS_PASSPHRASE_TEXT_SIZE_BYTES];
if (!keydb_get_volume_luks_passphrase(volume, luks_passphrase, sizeof(luks_passphrase))) {
OPENSSL_cleanse(luks_passphrase, sizeof(luks_passphrase));
@ -315,7 +366,7 @@ static enum cmd_returncode_t cmd_do_showkey_volume(struct volume_entry_t *volume
static enum cmd_returncode_t cmd_add_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 = cmd_gethost(ctx, host_name);
host_entry_t *host = cmd_gethost(ctx, host_name);
if (!host) {
return COMMAND_FAILURE;
}
@ -328,7 +379,7 @@ static enum cmd_returncode_t cmd_add_volume(struct editor_context_t *ctx, const
}
uint8_t volume_uuid[16];
parse_uuid(volume_uuid, volume_uuid_str);
struct volume_entry_t *volume = keydb_add_volume(host, devmapper_name, volume_uuid);
volume_entry_t *volume = keydb_add_volume(host, devmapper_name, volume_uuid);
if (volume) {
return cmd_do_showkey_volume(volume);
} else {
@ -340,7 +391,7 @@ static enum cmd_returncode_t cmd_del_volume(struct editor_context_t *ctx, const
const char *host_name = params[0];
const char *devmapper_name = params[1];
struct host_entry_t *host = cmd_gethost(ctx, host_name);
host_entry_t *host = cmd_gethost(ctx, host_name);
if (!host) {
return COMMAND_FAILURE;
}
@ -354,7 +405,7 @@ static enum cmd_returncode_t cmd_rekey_volume(struct editor_context_t *ctx, cons
const char *host_name = params[0];
const char *devmapper_name = params[1];
struct volume_entry_t *volume = cmd_getvolume(ctx, host_name, devmapper_name);
volume_entry_t *volume = cmd_getvolume(ctx, host_name, devmapper_name);
if (!volume) {
return COMMAND_FAILURE;
}
@ -368,7 +419,7 @@ static enum cmd_returncode_t cmd_showkey_volume(struct editor_context_t *ctx, co
const char *host_name = params[0];
const char *devmapper_name = params[1];
struct volume_entry_t *volume = cmd_getvolume(ctx, host_name, devmapper_name);
volume_entry_t *volume = cmd_getvolume(ctx, host_name, devmapper_name);
if (!volume) {
return COMMAND_FAILURE;
}
@ -376,6 +427,38 @@ static enum cmd_returncode_t cmd_showkey_volume(struct editor_context_t *ctx, co
return cmd_do_showkey_volume(volume);
}
static enum cmd_returncode_t cmd_flag_volume(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) {
const char *host_name = params[0];
const char *devmapper_name = params[1];
const char *flag_str = params[2];
volume_entry_t *volume = cmd_getvolume(ctx, host_name, devmapper_name);
if (!volume) {
return COMMAND_FAILURE;
}
if ((flag_str[0] != '+') && (flag_str[0] != '-')) {
fprintf(stderr, "Flag string must start with '+' or '-' for adding or removing a flag.\n");
return COMMAND_FAILURE;
}
unsigned int flag_value = 0;
if (!strcasecmp(flag_str + 1, "allow_discards")) {
flag_value = VOLUME_FLAG_ALLOW_DISCARDS;
} else {
fprintf(stderr, "Invalid flag '%s': allowed is only 'allow_discards'.\n", flag_str + 1);
return COMMAND_FAILURE;
}
if (flag_str[0] == '+') {
volume->volume_flags |= flag_value;
} else {
volume->volume_flags &= ~flag_value;
}
return COMMAND_SUCCESS;
}
static enum cmd_returncode_t cmd_open(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) {
if (ctx->keydb) {
keydb_free(ctx->keydb);
@ -417,12 +500,12 @@ static enum cmd_returncode_t cmd_save(struct editor_context_t *ctx, const char *
static enum cmd_returncode_t cmd_export(struct editor_context_t *ctx, const char *cmdname, unsigned int param_cnt, char **params) {
const char *host_name = params[0];
const char *filename = params[1];
struct host_entry_t *host = cmd_gethost(ctx, host_name);
host_entry_t *host = cmd_gethost(ctx, host_name);
if (!host) {
return COMMAND_FAILURE;
}
struct keydb_t *pubdb = keydb_export_public(host);
keydb_t *pubdb = keydb_export_public(host);
char passphrase[MAX_PASSPHRASE_LENGTH];
if (!query_passphrase("Client passphrase: ", passphrase, sizeof(passphrase))) {
fprintf(stderr, "Failed to read export passphrase.\n");
@ -471,9 +554,9 @@ static enum cmd_returncode_t cmd_rawdump(struct editor_context_t *ctx, const cha
if (!ctx->keydb) {
return COMMAND_SUCCESS;
}
fprintf(stderr, "Version %d, %s, %d hosts.\n", ctx->keydb->keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count);
fprintf(stderr, "Version %d, %s, %d hosts.\n", ctx->keydb->common.keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count);
for (unsigned int i = 0; i < ctx->keydb->host_count; i++) {
struct host_entry_t *host = &ctx->keydb->hosts[i];
host_entry_t *host = &ctx->keydb->hosts[i];
fprintf(stderr, "Host %d:\n", i);
{
char host_uuid[ASCII_UUID_BUFSIZE];
@ -488,8 +571,8 @@ static enum cmd_returncode_t cmd_rawdump(struct editor_context_t *ctx, const cha
dump_hexline(stderr, " tls_psk ", host->tls_psk, sizeof(host->tls_psk), false);
fprintf(stderr, " volume_count %u\n", host->volume_count);
for (unsigned int j = 0; j < MAX_VOLUMES_PER_HOST; j++) {
struct volume_entry_t *volume = &host->volumes[j];
if (!is_zero(volume, sizeof(struct volume_entry_t))) {
volume_entry_t *volume = &host->volumes[j];
if (!is_zero(volume, sizeof(volume_entry_t))) {
fprintf(stderr, " Host %d / Volume %d:\n", i, j);
dump_hexline(stderr, " volume_uuid ", volume->volume_uuid, sizeof(volume->volume_uuid), false);
dump_hexline(stderr, " devmapper_name ", volume->devmapper_name, sizeof(volume->devmapper_name), true);

173
keydb.c
View File

@ -33,23 +33,39 @@
#include "uuid.h"
#include "log.h"
static unsigned int keydb_getsize_v3_hostcount(unsigned int host_count) {
return sizeof(struct keydb_v3_t) + (host_count * sizeof(struct host_entry_v3_t));
}
static unsigned int keydb_getsize_v3(const struct keydb_v3_t *keydb) {
return keydb_getsize_v3_hostcount(keydb->host_count);
}
static unsigned int keydb_getsize_v2_hostcount(unsigned int host_count) {
return sizeof(struct keydb_v2_t) + (host_count * sizeof(struct host_entry_v2_t));
}
static unsigned int keydb_getsize_v2(const struct keydb_v2_t *keydb) {
return keydb_getsize_v2_hostcount(keydb->host_count);
}
static unsigned int keydb_getsize_hostcount(unsigned int host_count) {
return sizeof(struct keydb_t) + (host_count * sizeof(struct host_entry_t));
return keydb_getsize_v3_hostcount(host_count);
}
static unsigned int keydb_getsize(const struct keydb_t *keydb) {
return keydb_getsize_hostcount(keydb->host_count);
static unsigned int keydb_getsize(const keydb_t *keydb) {
return keydb_getsize_v3(keydb);
}
struct keydb_t* keydb_new(void) {
struct keydb_t *keydb = calloc(sizeof(struct keydb_t), 1);
keydb->keydb_version = KEYDB_VERSION;
keydb_t* keydb_new(void) {
keydb_t *keydb = calloc(sizeof(keydb_t), 1);
keydb->common.keydb_version = KEYDB_CURRENT_VERSION;
keydb->server_database = true;
return keydb;
}
struct keydb_t* keydb_export_public(struct host_entry_t *host) {
struct keydb_t *public_db = keydb_new();
keydb_t* keydb_export_public(host_entry_t *host) {
keydb_t *public_db = keydb_new();
if (!public_db) {
return NULL;
}
@ -61,28 +77,28 @@ struct keydb_t* keydb_export_public(struct host_entry_t *host) {
}
/* Copy over whole entry */
struct host_entry_t *public_host = &public_db->hosts[0];
host_entry_t *public_host = &public_db->hosts[0];
*public_host = *host;
/* But remove all LUKS passphrases of course, this is for the luksrku client */
for (unsigned int i = 0; i < host->volume_count; i++) {
struct volume_entry_t *volume = &public_host->volumes[i];
volume_entry_t *volume = &public_host->volumes[i];
memset(volume->luks_passphrase_raw, 0, sizeof(volume->luks_passphrase_raw));
}
return public_db;
}
void keydb_free(struct keydb_t *keydb) {
void keydb_free(keydb_t *keydb) {
if (keydb) {
OPENSSL_cleanse(keydb, keydb_getsize(keydb));
free(keydb);
}
}
struct volume_entry_t* keydb_get_volume_by_name(struct host_entry_t *host, const char *devmapper_name) {
volume_entry_t* keydb_get_volume_by_name(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];
volume_entry_t *volume = &host->volumes[i];
if (!strncasecmp(volume->devmapper_name, devmapper_name, sizeof(volume->devmapper_name) - 1)) {
return volume;
}
@ -90,9 +106,9 @@ struct volume_entry_t* keydb_get_volume_by_name(struct host_entry_t *host, const
return NULL;
}
struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name) {
host_entry_t* keydb_get_host_by_name(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];
host_entry_t *host = &keydb->hosts[i];
if (!strncasecmp(host->host_name, host_name, sizeof(host->host_name) - 1)) {
return host;
}
@ -100,9 +116,9 @@ struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *h
return NULL;
}
const struct volume_entry_t* keydb_get_volume_by_uuid(const struct host_entry_t *host, const uint8_t uuid[static 16]) {
const volume_entry_t* keydb_get_volume_by_uuid(const host_entry_t *host, const uint8_t uuid[static 16]) {
for (unsigned int i = 0; i < host->volume_count; i++) {
const struct volume_entry_t *volume = &host->volumes[i];
const volume_entry_t *volume = &host->volumes[i];
if (!memcmp(volume->volume_uuid, uuid, 16)) {
return volume;
}
@ -110,7 +126,7 @@ const struct volume_entry_t* keydb_get_volume_by_uuid(const struct host_entry_t
return NULL;
}
int keydb_get_host_index(const struct keydb_t *keydb, const struct host_entry_t *host) {
int keydb_get_host_index(const keydb_t *keydb, const host_entry_t *host) {
int index = host - keydb->hosts;
if (index < 0) {
return -1;
@ -120,7 +136,7 @@ int keydb_get_host_index(const struct keydb_t *keydb, const struct host_entry_t
return index;
}
int keydb_get_volume_index(const struct host_entry_t *host, const struct volume_entry_t *volume) {
int keydb_get_volume_index(const host_entry_t *host, const volume_entry_t *volume) {
int index = volume - host->volumes;
if (index < 0) {
return -1;
@ -130,9 +146,9 @@ int keydb_get_volume_index(const struct host_entry_t *host, const struct volume_
return index;
}
const struct host_entry_t* keydb_get_host_by_uuid(const struct keydb_t *keydb, const uint8_t uuid[static 16]) {
const host_entry_t* keydb_get_host_by_uuid(const keydb_t *keydb, const uint8_t uuid[static 16]) {
for (unsigned int i = 0; i < keydb->host_count; i++) {
const struct host_entry_t *host = &keydb->hosts[i];
const host_entry_t *host = &keydb->hosts[i];
if (!memcmp(host->host_uuid, uuid, 16)) {
return host;
}
@ -140,26 +156,26 @@ const struct host_entry_t* keydb_get_host_by_uuid(const struct keydb_t *keydb, c
return NULL;
}
bool keydb_add_host(struct keydb_t **keydb, const char *host_name) {
bool keydb_add_host(keydb_t **keydb, const char *host_name) {
if (strlen(host_name) > MAX_HOST_NAME_LENGTH - 1) {
log_msg(LLVL_ERROR, "Host name \"%s\" exceeds maximum length of %d characters.", host_name, MAX_HOST_NAME_LENGTH - 1);
return false;
}
struct keydb_t *old_keydb = *keydb;
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));
keydb_t *new_keydb = realloc(old_keydb, keydb_getsize_hostcount(old_keydb->host_count + 1));
if (!new_keydb) {
return false;
}
*keydb = new_keydb;
struct host_entry_t *host = &new_keydb->hosts[new_keydb->host_count];
memset(host, 0, sizeof(struct host_entry_t));
host_entry_t *host = &new_keydb->hosts[new_keydb->host_count];
memset(host, 0, sizeof(host_entry_t));
if (!uuid_randomize(host->host_uuid)) {
/* We keep the reallocation but do not increase the host count */
return false;
@ -174,9 +190,9 @@ bool keydb_add_host(struct keydb_t **keydb, const char *host_name) {
return true;
}
bool keydb_del_host_by_name(struct keydb_t **keydb, const char *host_name) {
struct keydb_t *old_keydb = *keydb;
struct host_entry_t *host = keydb_get_host_by_name(old_keydb, host_name);
bool keydb_del_host_by_name(keydb_t **keydb, const char *host_name) {
keydb_t *old_keydb = *keydb;
host_entry_t *host = keydb_get_host_by_name(old_keydb, host_name);
if (!host) {
log_msg(LLVL_ERROR, "No such host: \"%s\"", host_name);
return false;
@ -189,16 +205,16 @@ bool keydb_del_host_by_name(struct keydb_t **keydb, const char *host_name) {
}
/* We keep the memory for now and do not realloc */
array_remove(old_keydb->hosts, sizeof(struct host_entry_t), old_keydb->host_count, host_index);
array_remove(old_keydb->hosts, sizeof(host_entry_t), old_keydb->host_count, host_index);
old_keydb->host_count--;
return true;
}
bool keydb_rekey_host(struct host_entry_t *host) {
bool keydb_rekey_host(host_entry_t *host) {
return buffer_randomize(host->tls_psk, sizeof(host->tls_psk));
}
struct volume_entry_t* keydb_add_volume(struct host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]) {
volume_entry_t* keydb_add_volume(host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]) {
if (strlen(devmapper_name) > MAX_DEVMAPPER_NAME_LENGTH - 1) {
log_msg(LLVL_ERROR, "Device mapper name \"%s\" exceeds maximum length of %d characters.", devmapper_name, MAX_DEVMAPPER_NAME_LENGTH - 1);
return false;
@ -213,7 +229,7 @@ struct volume_entry_t* keydb_add_volume(struct host_entry_t *host, const char *d
return NULL;
}
struct volume_entry_t *volume = &host->volumes[host->volume_count];
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_raw, sizeof(volume->luks_passphrase_raw))) {
@ -224,8 +240,8 @@ struct volume_entry_t* keydb_add_volume(struct host_entry_t *host, const char *d
return volume;
}
bool keydb_del_volume(struct host_entry_t *host, const char *devmapper_name) {
struct volume_entry_t *volume = keydb_get_volume_by_name(host, devmapper_name);
bool keydb_del_volume(host_entry_t *host, const char *devmapper_name) {
volume_entry_t *volume = keydb_get_volume_by_name(host, devmapper_name);
if (!volume) {
log_msg(LLVL_ERROR, "No such volume \"%s\" for host \"%s\".", devmapper_name, host->host_name);
return false;
@ -235,7 +251,7 @@ bool keydb_del_volume(struct host_entry_t *host, const char *devmapper_name) {
log_msg(LLVL_FATAL, "Fatal error determining volume index of \"%s\" for host \"%s\".", devmapper_name, host->host_name);
return false;
}
if (!array_remove(host->volumes, sizeof(struct volume_entry_t), host->volume_count, index)) {
if (!array_remove(host->volumes, sizeof(volume_entry_t), host->volume_count, index)) {
log_msg(LLVL_ERROR, "Failed to remove \"%s\" of host \"%s\".", devmapper_name, host->host_name);
return false;
}
@ -243,15 +259,15 @@ bool keydb_del_volume(struct host_entry_t *host, const char *devmapper_name) {
return true;
}
bool keydb_rekey_volume(struct volume_entry_t *volume) {
bool keydb_rekey_volume(volume_entry_t *volume) {
return buffer_randomize(volume->luks_passphrase_raw, sizeof(volume->luks_passphrase_raw));
}
bool keydb_get_volume_luks_passphrase(const struct volume_entry_t *volume, char *dest, unsigned int dest_buffer_size) {
bool keydb_get_volume_luks_passphrase(const volume_entry_t *volume, char *dest, unsigned int dest_buffer_size) {
return ascii_encode(dest, dest_buffer_size, volume->luks_passphrase_raw, sizeof(volume->luks_passphrase_raw));
}
bool keydb_write(const struct keydb_t *keydb, const char *filename, const char *passphrase) {
bool keydb_write(const keydb_t *keydb, const char *filename, const char *passphrase) {
enum kdf_t kdf;
if ((!passphrase) || (strlen(passphrase) == 0)) {
/* For empty password, we can also use garbage KDF */
@ -266,26 +282,81 @@ static bool passphrase_callback(char *buffer, unsigned int bufsize) {
return query_passphrase("Database passphrase: ", buffer, bufsize);
}
struct keydb_t* keydb_read(const char *filename) {
static bool keydb_migrate_v2_to_v3(void **keydb_data, unsigned int *keydb_data_size) {
log_msg(LLVL_INFO, "Migrating keydb version 2 to version 3");
struct keydb_v2_t *old_db = *((struct keydb_v2_t **)keydb_data);
unsigned int new_db_size = keydb_getsize_v3_hostcount(old_db->host_count);
struct keydb_v3_t *new_db = calloc(1, new_db_size);
if (!new_db) {
log_msg(LLVL_ERROR, "keydb migration failed to allocate %d bytes of memory", new_db_size);
return false;
}
*new_db = (struct keydb_v3_t) {
.common.keydb_version = 3,
.server_database = old_db->server_database,
.host_count = old_db->host_count,
};
for (unsigned int i = 0; i < new_db->host_count; i++) {
/* Do not copy over host_flags or volumes */
memcpy(&new_db->hosts[i], &old_db->hosts[i], sizeof(old_db->hosts[i]) - sizeof(old_db->hosts[i].volumes));
for (unsigned int j = 0; j < new_db->hosts[i].volume_count; j++) {
/* Do not copy over volume_flags */
memcpy(&new_db->hosts[i].volumes[j], &old_db->hosts[i].volumes[j], sizeof(old_db->hosts[i].volumes[j]));
}
}
OPENSSL_cleanse(old_db, *keydb_data_size);
free(old_db);
*keydb_data = new_db;
*keydb_data_size = new_db_size;
return true;
}
static keydb_t* keydb_migrate(void **keydb_data, unsigned int *keydb_data_size) {
struct keydb_common_header_t *header;
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version == 2) {
if (*keydb_data_size != keydb_getsize_v2(*keydb_data)) {
log_msg(LLVL_ERROR, "keydb version 2 has wrong size (%u bytes, but expected %u bytes).", *keydb_data_size, keydb_getsize_v2(*keydb_data));
return NULL;
}
if (!keydb_migrate_v2_to_v3(keydb_data, keydb_data_size)) {
log_msg(LLVL_ERROR, "keydb version 2 to 3 migration failed.");
return NULL;
}
}
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version == 3) {
if (*keydb_data_size != keydb_getsize_v3(*keydb_data)) {
log_msg(LLVL_ERROR, "keydb version 3 has wrong size (%u bytes, but expected %u bytes).", *keydb_data_size, keydb_getsize_v3(*keydb_data));
return NULL;
}
}
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version != KEYDB_CURRENT_VERSION) {
log_msg(LLVL_ERROR, "keydb could be read, but is of version %u (we expected %u).", header->keydb_version, KEYDB_CURRENT_VERSION);
return NULL;
}
return *((keydb_t**)keydb_data);
}
keydb_t* keydb_read(const char *filename) {
struct decrypted_file_t decrypted_file = read_encrypted_file(filename, passphrase_callback);
if (!decrypted_file.success) {
return NULL;
}
struct keydb_t *keydb = (struct keydb_t*)decrypted_file.data;
if (keydb->keydb_version != KEYDB_VERSION) {
log_msg(LLVL_ERROR, "keydb in %s could be read, but is of version %u (we expected %u).", filename, keydb->keydb_version, KEYDB_VERSION);
keydb_t *keydb = keydb_migrate(&decrypted_file.data, &decrypted_file.data_length);
if (!keydb) {
OPENSSL_cleanse(decrypted_file.data, decrypted_file.data_length);
free(decrypted_file.data);
return NULL;
}
if (decrypted_file.data_length != keydb_getsize(keydb)) {
log_msg(LLVL_ERROR, "keydb in %s could be read, but was %u bytes long (we expected %u).", filename, decrypted_file.data_length, keydb_getsize(keydb));
OPENSSL_cleanse(decrypted_file.data, decrypted_file.data_length);
free(decrypted_file.data);
return NULL;
}
return keydb;
}

100
keydb.h
View File

@ -30,48 +30,92 @@
#include "file_encryption.h"
#include "global.h"
#define KEYDB_VERSION 2
#define ALIGNED __attribute__ ((aligned(4)))
struct volume_entry_t {
enum volume_flag_t {
VOLUME_FLAG_ALLOW_DISCARDS = (1 << 0),
};
/* Unused so far */
enum host_flag_t {
HOST_FLAG_UNUSED = 0,
};
struct keydb_common_header_t {
unsigned int keydb_version;
} ALIGNED;
struct volume_entry_v2_t {
uint8_t volume_uuid[16]; /* UUID of crypt_LUKS volume */
char devmapper_name[MAX_DEVMAPPER_NAME_LENGTH]; /* dmsetup name when unlocked. Zero-terminated string. */
uint8_t luks_passphrase_raw[LUKS_PASSPHRASE_RAW_SIZE_BYTES]; /* LUKS passphrase used to unlock volume; raw byte data */
};
} ALIGNED;
struct host_entry_t {
struct host_entry_v2_t {
uint8_t host_uuid[16]; /* Host UUID */
char host_name[MAX_HOST_NAME_LENGTH]; /* Descriptive name of host */
uint8_t tls_psk[PSK_SIZE_BYTES]; /* Raw byte data of TLS-PSK that is used */
unsigned int volume_count; /* Number of volumes of this host */
struct volume_entry_t volumes[MAX_VOLUMES_PER_HOST]; /* Volumes of this host */
};
struct volume_entry_v2_t volumes[MAX_VOLUMES_PER_HOST]; /* Volumes of this host */
} ALIGNED;
struct keydb_t {
unsigned int keydb_version;
struct keydb_v2_t {
struct keydb_common_header_t common;
bool server_database;
unsigned int host_count;
struct host_entry_t hosts[];
};
struct host_entry_v2_t hosts[];
} ALIGNED;
struct volume_entry_v3_t {
uint8_t volume_uuid[16]; /* UUID of crypt_LUKS volume */
char devmapper_name[MAX_DEVMAPPER_NAME_LENGTH]; /* dmsetup name when unlocked. Zero-terminated string. */
uint8_t luks_passphrase_raw[LUKS_PASSPHRASE_RAW_SIZE_BYTES]; /* LUKS passphrase used to unlock volume; raw byte data */
unsigned int volume_flags; /* Bitset of enum volume_flag_t */
} ALIGNED;
struct host_entry_v3_t {
uint8_t host_uuid[16]; /* Host UUID */
char host_name[MAX_HOST_NAME_LENGTH]; /* Descriptive name of host */
uint8_t tls_psk[PSK_SIZE_BYTES]; /* Raw byte data of TLS-PSK that is used */
unsigned int volume_count; /* Number of volumes of this host */
unsigned int client_default_timeout_secs; /* Client gives up by default if not everything unlocked after this time */
unsigned int host_flags; /* Bitset of enum host_flag_t */
struct volume_entry_v3_t volumes[MAX_VOLUMES_PER_HOST]; /* Volumes of this host */
} ALIGNED;
struct keydb_v3_t {
struct keydb_common_header_t common;
bool server_database;
unsigned int host_count;
struct host_entry_v3_t hosts[];
} ALIGNED;
#define KEYDB_CURRENT_VERSION 3
typedef struct volume_entry_v3_t volume_entry_t;
typedef struct host_entry_v3_t host_entry_t;
typedef struct keydb_v3_t keydb_t;
/*************** AUTO GENERATED SECTION FOLLOWS ***************/
struct keydb_t* keydb_new(void);
struct keydb_t* keydb_export_public(struct host_entry_t *host);
void keydb_free(struct keydb_t *keydb);
struct volume_entry_t* keydb_get_volume_by_name(struct host_entry_t *host, const char *devmapper_name);
struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name);
const struct volume_entry_t* keydb_get_volume_by_uuid(const struct host_entry_t *host, const uint8_t uuid[static 16]);
int keydb_get_host_index(const struct keydb_t *keydb, const struct host_entry_t *host);
int keydb_get_volume_index(const struct host_entry_t *host, const struct volume_entry_t *volume);
const struct host_entry_t* keydb_get_host_by_uuid(const struct keydb_t *keydb, const uint8_t uuid[static 16]);
bool keydb_add_host(struct keydb_t **keydb, const char *host_name);
bool keydb_del_host_by_name(struct keydb_t **keydb, const char *host_name);
bool keydb_rekey_host(struct host_entry_t *host);
struct volume_entry_t* keydb_add_volume(struct host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]);
bool keydb_del_volume(struct host_entry_t *host, const char *devmapper_name);
bool keydb_rekey_volume(struct volume_entry_t *volume);
bool keydb_get_volume_luks_passphrase(const struct volume_entry_t *volume, char *dest, unsigned int dest_buffer_size);
bool keydb_write(const struct keydb_t *keydb, const char *filename, const char *passphrase);
struct keydb_t* keydb_read(const char *filename);
keydb_t* keydb_new(void);
keydb_t* keydb_export_public(host_entry_t *host);
void keydb_free(keydb_t *keydb);
volume_entry_t* keydb_get_volume_by_name(host_entry_t *host, const char *devmapper_name);
host_entry_t* keydb_get_host_by_name(keydb_t *keydb, const char *host_name);
const volume_entry_t* keydb_get_volume_by_uuid(const host_entry_t *host, const uint8_t uuid[static 16]);
int keydb_get_host_index(const keydb_t *keydb, const host_entry_t *host);
int keydb_get_volume_index(const host_entry_t *host, const volume_entry_t *volume);
const host_entry_t* keydb_get_host_by_uuid(const keydb_t *keydb, const uint8_t uuid[static 16]);
bool keydb_add_host(keydb_t **keydb, const char *host_name);
bool keydb_del_host_by_name(keydb_t **keydb, const char *host_name);
bool keydb_rekey_host(host_entry_t *host);
volume_entry_t* keydb_add_volume(host_entry_t *host, const char *devmapper_name, const uint8_t volume_uuid[static 16]);
bool keydb_del_volume(host_entry_t *host, const char *devmapper_name);
bool keydb_rekey_volume(volume_entry_t *volume);
bool keydb_get_volume_luks_passphrase(const volume_entry_t *volume, char *dest, unsigned int dest_buffer_size);
bool keydb_write(const keydb_t *keydb, const char *filename, const char *passphrase);
keydb_t* keydb_read(const char *filename);
/*************** AUTO GENERATED SECTION ENDS ***************/
#endif

14
luks.c
View File

@ -50,25 +50,35 @@ bool is_luks_device_opened(const char *mapping_name) {
return runresult.success && (runresult.returncode == 0);
}
bool open_luks_device(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length) {
bool open_luks_device(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length, bool allow_discards) {
char encrypted_device[64];
strcpy(encrypted_device, "UUID=");
sprintf_uuid(encrypted_device + 5, encrypted_device_uuid);
log_msg(LLVL_INFO, "Trying to unlock LUKS mapping %s based on %s", mapping_name, encrypted_device);
struct exec_cmd_t cmd = {
.argv = (const char *[]){
.argv = !allow_discards ? (const char *[]) {
"cryptsetup",
"luksOpen",
"-T", "1",
encrypted_device,
mapping_name,
NULL,
} :
(const char *[]) {
"cryptsetup",
"--allow-discards",
"luksOpen",
"-T", "1",
encrypted_device,
mapping_name,
NULL,
},
.stdin_data = passphrase,
.stdin_length = passphrase_length,
.show_output = should_log(LLVL_DEBUG),
};
struct exec_result_t runresult = exec_command(&cmd);
return runresult.success && (runresult.returncode == 0);
}

2
luks.h
View File

@ -29,7 +29,7 @@
/*************** AUTO GENERATED SECTION FOLLOWS ***************/
bool is_luks_device_opened(const char *mapping_name);
bool open_luks_device(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length);
bool open_luks_device(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length, bool allow_discards);
/*************** AUTO GENERATED SECTION ENDS ***************/
#endif

View File

@ -1,6 +1,6 @@
import argparse
parser = argparse.ArgumentParser(prog = "luksrku client", description = "Connects to a luksrku key server and unlocks local LUKS volumes.", add_help = False)
parser.add_argument("-t", "--timeout", metavar = "secs", default = 60, help = "When searching for a keyserver and not all volumes can be unlocked, abort after this period of time, given in seconds. Defaults to %(default)d seconds.")
parser.add_argument("-t", "--timeout", metavar = "secs", default = 0, help = "When searching for a keyserver and not all volumes can be unlocked, abort after this period of time, given in seconds. Defaults to infinity. This argument can be specified as a host-based configuration parameter as well; the command-line argument always takes precedence.")
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("--no-luks", action = "store_true", help = "Do not call LUKS/cryptsetup. Useful for testing unlocking procedure.")
parser.add_argument("-v", "--verbose", action = "count", default = 0, help = "Increase verbosity. Can be specified multiple times.")

View File

@ -52,7 +52,7 @@
#include "vaulted_keydb.h"
struct keyserver_t {
struct keydb_t* keydb;
keydb_t* keydb;
struct vaulted_keydb_t *vaulted_keydb;
struct generic_tls_ctx_t gctx;
const struct pgmopts_server_t *opts;
@ -61,14 +61,14 @@ struct keyserver_t {
struct client_thread_ctx_t {
struct generic_tls_ctx_t *gctx;
const struct keydb_t *keydb;
const keydb_t *keydb;
struct vaulted_keydb_t *vaulted_keydb;
const struct host_entry_t *host;
const host_entry_t *host;
int fd;
};
struct udp_listen_thread_ctx_t {
const struct keydb_t *keydb;
const keydb_t *keydb;
int udp_sd;
unsigned int port;
};
@ -165,7 +165,7 @@ static void client_handler_thread(void *vctx) {
* client by filling the UUID fields */
struct msg_t msgs[client->host->volume_count];
for (unsigned int i = 0; i < client->host->volume_count; i++) {
const struct volume_entry_t *volume = &client->host->volumes[i];
const volume_entry_t *volume = &client->host->volumes[i];
memcpy(msgs[i].volume_uuid, volume->volume_uuid, 16);
}

View File

@ -35,9 +35,9 @@ static struct luks_passphrase_vault_entry_t *vaulted_keydb_get_luks_passphrase_f
return ((struct luks_passphrase_vault_entry_t*)vkeydb->luks_passphrase_vault->data) + host_index;
}
static void move_data_into_vault(struct vaulted_keydb_t *dest, struct keydb_t *src) {
static void move_data_into_vault(struct vaulted_keydb_t *dest, keydb_t *src) {
for (unsigned int i = 0; i < src->host_count; i++) {
struct host_entry_t *host = &src->hosts[i];
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);
@ -47,14 +47,14 @@ static void move_data_into_vault(struct vaulted_keydb_t *dest, struct keydb_t *s
/* 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];
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);
}
}
}
bool vaulted_keydb_get_tls_psk(struct vaulted_keydb_t *vaulted_keydb, uint8_t dest[PSK_SIZE_BYTES], const struct host_entry_t *host) {
bool vaulted_keydb_get_tls_psk(struct vaulted_keydb_t *vaulted_keydb, uint8_t dest[PSK_SIZE_BYTES], const host_entry_t *host) {
int host_index = keydb_get_host_index(vaulted_keydb->keydb, host);
if (host_index < 0) {
log_msg(LLVL_FATAL, "Unable to retrieve host index for vaulted key db entry.");
@ -83,7 +83,7 @@ bool vaulted_keydb_get_tls_psk(struct vaulted_keydb_t *vaulted_keydb, uint8_t de
return true;
}
bool vaulted_keydb_get_volume_luks_passphases_raw(struct vaulted_keydb_t *vaulted_keydb, void (*copy_callback)(void *vctx, unsigned int volume_index, const void *source), void *copy_ctx, const struct host_entry_t *host) {
bool vaulted_keydb_get_volume_luks_passphases_raw(struct vaulted_keydb_t *vaulted_keydb, void (*copy_callback)(void *vctx, unsigned int volume_index, const void *source), void *copy_ctx, const host_entry_t *host) {
int host_index = keydb_get_host_index(vaulted_keydb->keydb, host);
if (host_index < 0) {
log_msg(LLVL_FATAL, "Unable to retrieve host index for vaulted key db entry.");
@ -112,7 +112,7 @@ bool vaulted_keydb_get_volume_luks_passphases_raw(struct vaulted_keydb_t *vaulte
return true;
}
struct vaulted_keydb_t *vaulted_keydb_new(struct keydb_t *keydb) {
struct vaulted_keydb_t *vaulted_keydb_new(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");

View File

@ -38,15 +38,15 @@ struct luks_passphrase_vault_entry_t {
};
struct vaulted_keydb_t {
struct keydb_t *keydb;
keydb_t *keydb;
struct vault_t *tls_psk_vault;
struct vault_t *luks_passphrase_vault;
};
/*************** AUTO GENERATED SECTION FOLLOWS ***************/
bool vaulted_keydb_get_tls_psk(struct vaulted_keydb_t *vaulted_keydb, uint8_t dest[PSK_SIZE_BYTES], const struct host_entry_t *host);
bool vaulted_keydb_get_volume_luks_passphases_raw(struct vaulted_keydb_t *vaulted_keydb, void (*copy_callback)(void *ctx, unsigned int volume_index, const void *source), void *copy_ctx, const struct host_entry_t *host);
struct vaulted_keydb_t *vaulted_keydb_new(struct keydb_t *keydb);
bool vaulted_keydb_get_tls_psk(struct vaulted_keydb_t *vaulted_keydb, uint8_t dest[PSK_SIZE_BYTES], const host_entry_t *host);
bool vaulted_keydb_get_volume_luks_passphases_raw(struct vaulted_keydb_t *vaulted_keydb, void (*copy_callback)(void *ctx, unsigned int volume_index, const void *source), void *copy_ctx, const host_entry_t *host);
struct vaulted_keydb_t *vaulted_keydb_new(keydb_t *keydb);
void vaulted_keydb_free(struct vaulted_keydb_t *vaulted_keydb);
/*************** AUTO GENERATED SECTION ENDS ***************/