Implemented finding of keyserver and unlocking of volumes

We'll now parse the response messages on the client side, abort after a
previously defined timeout and trigger the LUKS unlocking process, if
requested (although the latter isn't fully implemented yet).
This commit is contained in:
Johannes Bauer 2019-10-25 11:08:20 +02:00
parent 05e112065e
commit 849e3a5949
21 changed files with 209 additions and 69 deletions

View File

@ -48,7 +48,7 @@ test_s: luksrku
./luksrku server -vv testdata/server.bin ./luksrku server -vv testdata/server.bin
test_c: luksrku test_c: luksrku
./luksrku client -vv testdata/client.bin ./luksrku client -vv --no-luks testdata/client.bin
.c.o: .c.o:
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<

View File

@ -22,7 +22,7 @@ passphrases are based on 256 bit long secrets and are converted to Base64 for
easier handling (when setting up everything initially). easier handling (when setting up everything initially).
The binary protocol that runs between both is intentionally extremely simple to The binary protocol that runs between both is intentionally extremely simple to
allow for easy code review. allow for easy code review. It exclusively uses fixed message lengths.
The key database is encrypted itself, using AES256-GCM, a 128 bit randomized The key database is encrypted itself, using AES256-GCM, a 128 bit randomized
initialization vector and authenticated with a 128 bit authentication tag. Key initialization vector and authenticated with a 128 bit authentication tag. Key

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#include <stdint.h> #include <stdint.h>
@ -21,19 +21,24 @@
static enum argparse_client_option_t last_parsed_option; static enum argparse_client_option_t last_parsed_option;
static char last_error_message[256]; static char last_error_message[256];
static const char *option_texts[] = { static const char *option_texts[] = {
[ARG_CLIENT_TIMEOUT] = "-t / --timeout",
[ARG_CLIENT_PORT] = "-p / --port", [ARG_CLIENT_PORT] = "-p / --port",
[ARG_CLIENT_NO_LUKS] = "--no-luks",
[ARG_CLIENT_VERBOSE] = "-v / --verbose", [ARG_CLIENT_VERBOSE] = "-v / --verbose",
[ARG_CLIENT_FILENAME] = "filename", [ARG_CLIENT_FILENAME] = "filename",
[ARG_CLIENT_HOSTNAME] = "hostname", [ARG_CLIENT_HOSTNAME] = "hostname",
}; };
enum argparse_client_option_internal_t { enum argparse_client_option_internal_t {
ARG_CLIENT_TIMEOUT_SHORT = 't',
ARG_CLIENT_PORT_SHORT = 'p', ARG_CLIENT_PORT_SHORT = 'p',
ARG_CLIENT_VERBOSE_SHORT = 'v', ARG_CLIENT_VERBOSE_SHORT = 'v',
ARG_CLIENT_PORT_LONG = 1000, ARG_CLIENT_TIMEOUT_LONG = 1000,
ARG_CLIENT_VERBOSE_LONG = 1001, ARG_CLIENT_PORT_LONG = 1001,
ARG_CLIENT_FILENAME_LONG = 1002, ARG_CLIENT_NO_LUKS_LONG = 1002,
ARG_CLIENT_HOSTNAME_LONG = 1003, ARG_CLIENT_VERBOSE_LONG = 1003,
ARG_CLIENT_FILENAME_LONG = 1004,
ARG_CLIENT_HOSTNAME_LONG = 1005,
}; };
static void errmsg_callback(const char *errmsg, ...) { static void errmsg_callback(const char *errmsg, ...) {
@ -54,9 +59,11 @@ static void errmsg_option_callback(enum argparse_client_option_t error_option, c
bool argparse_client_parse(int argc, char **argv, argparse_client_callback_t argument_callback, argparse_client_plausibilization_callback_t plausibilization_callback) { bool argparse_client_parse(int argc, char **argv, argparse_client_callback_t argument_callback, argparse_client_plausibilization_callback_t plausibilization_callback) {
last_parsed_option = ARGPARSE_CLIENT_NO_OPTION; last_parsed_option = ARGPARSE_CLIENT_NO_OPTION;
const char *short_options = "p:v"; const char *short_options = "t:p:v";
struct option long_options[] = { struct option long_options[] = {
{ "timeout", required_argument, 0, ARG_CLIENT_TIMEOUT_LONG },
{ "port", required_argument, 0, ARG_CLIENT_PORT_LONG }, { "port", required_argument, 0, ARG_CLIENT_PORT_LONG },
{ "no-luks", no_argument, 0, ARG_CLIENT_NO_LUKS_LONG },
{ "verbose", no_argument, 0, ARG_CLIENT_VERBOSE_LONG }, { "verbose", no_argument, 0, ARG_CLIENT_VERBOSE_LONG },
{ "filename", required_argument, 0, ARG_CLIENT_FILENAME_LONG }, { "filename", required_argument, 0, ARG_CLIENT_FILENAME_LONG },
{ "hostname", required_argument, 0, ARG_CLIENT_HOSTNAME_LONG }, { "hostname", required_argument, 0, ARG_CLIENT_HOSTNAME_LONG },
@ -71,6 +78,14 @@ bool argparse_client_parse(int argc, char **argv, argparse_client_callback_t arg
last_error_message[0] = 0; last_error_message[0] = 0;
enum argparse_client_option_internal_t arg = (enum argparse_client_option_internal_t)optval; enum argparse_client_option_internal_t arg = (enum argparse_client_option_internal_t)optval;
switch (arg) { switch (arg) {
case ARG_CLIENT_TIMEOUT_SHORT:
case ARG_CLIENT_TIMEOUT_LONG:
last_parsed_option = ARG_CLIENT_TIMEOUT;
if (!argument_callback(ARG_CLIENT_TIMEOUT, optarg, errmsg_callback)) {
return false;
}
break;
case ARG_CLIENT_PORT_SHORT: case ARG_CLIENT_PORT_SHORT:
case ARG_CLIENT_PORT_LONG: case ARG_CLIENT_PORT_LONG:
last_parsed_option = ARG_CLIENT_PORT; last_parsed_option = ARG_CLIENT_PORT;
@ -79,6 +94,13 @@ bool argparse_client_parse(int argc, char **argv, argparse_client_callback_t arg
} }
break; break;
case ARG_CLIENT_NO_LUKS_LONG:
last_parsed_option = ARG_CLIENT_NO_LUKS;
if (!argument_callback(ARG_CLIENT_NO_LUKS, optarg, errmsg_callback)) {
return false;
}
break;
case ARG_CLIENT_VERBOSE_SHORT: case ARG_CLIENT_VERBOSE_SHORT:
case ARG_CLIENT_VERBOSE_LONG: case ARG_CLIENT_VERBOSE_LONG:
last_parsed_option = ARG_CLIENT_VERBOSE; last_parsed_option = ARG_CLIENT_VERBOSE;
@ -127,7 +149,7 @@ bool argparse_client_parse(int argc, char **argv, argparse_client_callback_t arg
} }
void argparse_client_show_syntax(void) { void argparse_client_show_syntax(void) {
fprintf(stderr, "usage: luksrku client [-p port] [-v] filename [hostname]\n"); fprintf(stderr, "usage: luksrku client [-t secs] [-p port] [--no-luks] [-v] filename [hostname]\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Connects to a luksrku key server and unlocks local LUKS volumes.\n"); fprintf(stderr, "Connects to a luksrku key server and unlocks local LUKS volumes.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@ -139,8 +161,14 @@ void argparse_client_show_syntax(void) {
fprintf(stderr, " hostname is attempted.\n"); fprintf(stderr, " hostname is attempted.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "optional arguments:\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, " -p port, --port port Port that is used for both UDP and TCP communication.\n");
fprintf(stderr, " Defaults to 23170.\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, " -v, --verbose Increase verbosity. Can be specified multiple times.\n"); fprintf(stderr, " -v, --verbose Increase verbosity. Can be specified multiple times.\n");
} }
@ -166,7 +194,9 @@ void argparse_client_parse_or_quit(int argc, char **argv, argparse_client_callba
static const char *option_enum_to_str(enum argparse_client_option_t option) { static const char *option_enum_to_str(enum argparse_client_option_t option) {
switch (option) { switch (option) {
case ARG_CLIENT_TIMEOUT: return "ARG_CLIENT_TIMEOUT";
case ARG_CLIENT_PORT: return "ARG_CLIENT_PORT"; case ARG_CLIENT_PORT: return "ARG_CLIENT_PORT";
case ARG_CLIENT_NO_LUKS: return "ARG_CLIENT_NO_LUKS";
case ARG_CLIENT_VERBOSE: return "ARG_CLIENT_VERBOSE"; case ARG_CLIENT_VERBOSE: return "ARG_CLIENT_VERBOSE";
case ARG_CLIENT_FILENAME: return "ARG_CLIENT_FILENAME"; case ARG_CLIENT_FILENAME: return "ARG_CLIENT_FILENAME";
case ARG_CLIENT_HOSTNAME: return "ARG_CLIENT_HOSTNAME"; case ARG_CLIENT_HOSTNAME: return "ARG_CLIENT_HOSTNAME";

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#ifndef __ARGPARSE_CLIENT_H__ #ifndef __ARGPARSE_CLIENT_H__
@ -13,6 +13,7 @@
#include <stdbool.h> #include <stdbool.h>
#define ARGPARSE_CLIENT_DEFAULT_TIMEOUT 60
#define ARGPARSE_CLIENT_DEFAULT_PORT 23170 #define ARGPARSE_CLIENT_DEFAULT_PORT 23170
#define ARGPARSE_CLIENT_DEFAULT_VERBOSE 0 #define ARGPARSE_CLIENT_DEFAULT_VERBOSE 0
@ -20,10 +21,12 @@
#define ARGPARSE_CLIENT_POSITIONAL_ARG 1 #define ARGPARSE_CLIENT_POSITIONAL_ARG 1
enum argparse_client_option_t { enum argparse_client_option_t {
ARG_CLIENT_PORT = 2, ARG_CLIENT_TIMEOUT = 2,
ARG_CLIENT_VERBOSE = 3, ARG_CLIENT_PORT = 3,
ARG_CLIENT_FILENAME = 4, ARG_CLIENT_NO_LUKS = 4,
ARG_CLIENT_HOSTNAME = 5, ARG_CLIENT_VERBOSE = 5,
ARG_CLIENT_FILENAME = 6,
ARG_CLIENT_HOSTNAME = 7,
}; };
typedef void (*argparse_client_errmsg_callback_t)(const char *errmsg, ...); typedef void (*argparse_client_errmsg_callback_t)(const char *errmsg, ...);

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#include <stdint.h> #include <stdint.h>

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#ifndef __ARGPARSE_EDIT_H__ #ifndef __ARGPARSE_EDIT_H__

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#include <stdint.h> #include <stdint.h>

View File

@ -5,7 +5,7 @@
* *
* Do not edit it by hand, your changes will be overwritten. * Do not edit it by hand, your changes will be overwritten.
* *
* Generated at: 2019-10-23 20:13:13 * Generated at: 2019-10-25 11:06:30
*/ */
#ifndef __ARGPARSE_SERVER_H__ #ifndef __ARGPARSE_SERVER_H__

View File

@ -24,20 +24,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/time.h>
#include "blacklist.h" #include "blacklist.h"
#include "global.h" #include "global.h"
#include "util.h"
static struct blacklist_entry_t blacklist[BLACKLIST_ENTRY_COUNT]; static struct blacklist_entry_t blacklist[BLACKLIST_ENTRY_COUNT];
static double now(void) {
struct timeval tv;
if (gettimeofday(&tv, NULL)) {
return 0;
}
return tv.tv_sec + (tv.tv_usec * 1e-6);
}
static bool blacklist_entry_expired(int index) { static bool blacklist_entry_expired(int index) {
return now() > blacklist[index].entered + BLACKLIST_ENTRY_TIMEOUT_SECS; return now() > blacklist[index].entered + BLACKLIST_ENTRY_TIMEOUT_SECS;
} }

View File

@ -28,7 +28,7 @@
#include <stdbool.h> #include <stdbool.h>
#define BLACKLIST_ENTRY_COUNT 32 #define BLACKLIST_ENTRY_COUNT 32
#define BLACKLIST_ENTRY_TIMEOUT_SECS 60 #define BLACKLIST_ENTRY_TIMEOUT_SECS 15
struct blacklist_entry_t { struct blacklist_entry_t {
uint32_t ip; uint32_t ip;

111
client.c
View File

@ -42,12 +42,14 @@
#include "blacklist.h" #include "blacklist.h"
#include "keydb.h" #include "keydb.h"
#include "uuid.h" #include "uuid.h"
#include "udp.h"
struct keyclient_t { struct keyclient_t {
const struct pgmopts_client_t *opts; const struct pgmopts_client_t *opts;
struct keydb_t *keydb; struct keydb_t *keydb;
bool volume_unlocked[MAX_VOLUMES_PER_HOST]; bool volume_unlocked[MAX_VOLUMES_PER_HOST];
unsigned char identifier[ASCII_UUID_BUFSIZE]; unsigned char identifier[ASCII_UUID_BUFSIZE];
double broadcast_start_time;
}; };
static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sessptr) { static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sessptr) {
@ -58,6 +60,36 @@ 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); return openssl_tls13_psk_establish_session(ssl, key_client->keydb->hosts[0].tls_psk, PSK_SIZE_BYTES, EVP_sha256(), sessptr);
} }
static bool do_unlock_luks_volume(const struct volume_entry_t *volume, const struct msg_t *unlock_msg) {
return true;
}
static bool 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);
if (!volume) {
char volume_uuid_str[ASCII_UUID_BUFSIZE];
sprintf_uuid(volume_uuid_str, unlock_msg->volume_uuid);
log_msg(LLVL_WARNING, "Keyserver provided key for unlocking volume UUID %s, but this volume does not need unlocking on the client side.", volume_uuid_str);
return false;
}
/* Volume! */
int volume_index = keydb_get_volume_index(host, volume);
if (volume_index != -1) {
if (keyclient->opts->no_luks) {
keyclient->volume_unlocked[volume_index] = true;
} else {
keyclient->volume_unlocked[volume_index] = do_unlock_luks_volume(volume, unlock_msg);
}
} else {
log_msg(LLVL_FATAL, "Error calculating volume offset for volume %p from base %p.", volume, host->volumes);
return false;
}
return true;
}
static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) { static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) {
struct generic_tls_ctx_t gctx; struct generic_tls_ctx_t gctx;
if (!create_generic_tls_context(&gctx, false)) { if (!create_generic_tls_context(&gctx, false)) {
@ -83,10 +115,13 @@ static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) {
log_openssl(LLVL_FATAL, "SSL_read returned %d bytes when we expected to read %d", bytes_read, sizeof(msg)); log_openssl(LLVL_FATAL, "SSL_read returned %d bytes when we expected to read %d", bytes_read, sizeof(msg));
break; break;
} }
if (should_log(LLVL_TRACE)) { char uuid_str[ASCII_UUID_BUFSIZE];
char uuid_str[ASCII_UUID_BUFSIZE]; sprintf_uuid(uuid_str, msg.volume_uuid);
sprintf_uuid(uuid_str, msg.volume_uuid); log_msg(LLVL_TRACE, "Received LUKS key to unlock volume with UUID %s", uuid_str);
log_msg(LLVL_TRACE, "Received LUKS key to unlock volume with UUID %s", uuid_str); if (unlock_luks_volume(keyclient, &msg)) {
log_msg(LLVL_DEBUG, "Successfully unlocked volume with UUID %s", uuid_str);
} else {
log_msg(LLVL_ERROR, "Failed to unlocked volume with UUID %s", uuid_str);
} }
} }
OPENSSL_cleanse(&msg, sizeof(msg)); OPENSSL_cleanse(&msg, sizeof(msg));
@ -152,50 +187,62 @@ static bool contact_keyserver_hostname(struct keyclient_t *keyclient, const char
return success; return success;
} }
static int create_udp_socket(void) { static bool all_volumes_unlocked(struct keyclient_t *keyclient) {
int sd = socket(AF_INET, SOCK_DGRAM, 0); const unsigned int volume_count = keyclient->keydb->hosts[0].volume_count;
if (sd < 0) { for (unsigned int i = 0; i < volume_count; i++) {
log_libc(LLVL_ERROR, "Unable to create UDP server socket(2)"); if (!keyclient->volume_unlocked[i]) {
return -1; return false;
}
{
int value = 1;
if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value))) {
log_libc(LLVL_ERROR, "Unable to set UDP socket in broadcast mode using setsockopt(2)");
close(sd);
return -1;
} }
} }
return sd;
}
static bool send_udp_broadcast_message(int sd, unsigned int port, const void *data, unsigned int length) {
struct sockaddr_in destination;
memset(&destination, 0, sizeof(struct sockaddr_in));
destination.sin_family = AF_INET;
destination.sin_port = htons(port);
destination.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (sendto(sd, data, length, 0, (struct sockaddr *)&destination, sizeof(struct sockaddr_in)) < 0) {
log_libc(LLVL_ERROR, "Unable to sendto(2)");
return false;
}
return true; return true;
} }
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) {
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.", keyclient->opts->timeout_seconds);
return true;
}
}
return false;
}
static bool broadcast_for_keyserver(struct keyclient_t *keyclient) { static bool broadcast_for_keyserver(struct keyclient_t *keyclient) {
int sd = create_udp_socket(); int sd = create_udp_socket(0, true, 1000);
if (sd == -1) { if (sd == -1) {
return false; return false;
} }
keyclient->broadcast_start_time = now();
struct udp_query_t query; struct udp_query_t query;
memcpy(query.magic, UDP_MESSAGE_MAGIC, sizeof(query.magic)); memcpy(query.magic, UDP_MESSAGE_MAGIC, sizeof(query.magic));
memcpy(query.host_uuid, keyclient->keydb->hosts[0].host_uuid, 16); memcpy(query.host_uuid, keyclient->keydb->hosts[0].host_uuid, 16);
while (true) { while (true) {
send_udp_broadcast_message(sd, keyclient->opts->port, &query, sizeof(query)); send_udp_broadcast_message(sd, keyclient->opts->port, &query, sizeof(query));
sleep(1);
struct sockaddr_in src = {
.sin_family = AF_INET,
.sin_port = htons(keyclient->opts->port),
.sin_addr.s_addr = htonl(INADDR_ANY),
};
struct udp_response_t response;
if (wait_udp_response(sd, &response, &src)) {
log_msg(LLVL_DEBUG, "Potential keyserver found at %d.%d.%d.%d", PRINTF_FORMAT_IP(&src));
if (!contact_keyserver_ipv4(keyclient, &src, keyclient->opts->port)) {
log_msg(LLVL_WARNING, "Keyserver announced at %d.%d.%d.%d, but connection to it failed.", PRINTF_FORMAT_IP(&src));
}
}
if (abort_searching_for_keyserver(keyclient)) {
break;
}
} }
return true; return true;
} }

20
keydb.c
View File

@ -105,6 +105,26 @@ struct volume_entry_t* keydb_get_volume_by_name(struct host_entry_t *host, const
return (index >= 0) ? &host->volumes[index] : NULL; return (index >= 0) ? &host->volumes[index] : NULL;
} }
const struct volume_entry_t* keydb_get_volume_by_uuid(const struct 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];
if (!memcmp(volume->volume_uuid, uuid, 16)) {
return volume;
}
}
return NULL;
}
int keydb_get_volume_index(const struct host_entry_t *host, const struct volume_entry_t *volume) {
int offset = volume - host->volumes;
if (offset < 0) {
return -1;
} else if ((unsigned int)offset >= host->volume_count) {
return -1;
}
return offset;
}
struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name) { 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); const int index = keydb_get_host_index_by_name(keydb, host_name);
return (index >= 0) ? &keydb->hosts[index] : NULL; return (index >= 0) ? &keydb->hosts[index] : NULL;

View File

@ -58,6 +58,8 @@ struct keydb_t* keydb_new(void);
struct keydb_t* keydb_export_public(struct host_entry_t *host); struct keydb_t* keydb_export_public(struct host_entry_t *host);
void keydb_free(struct keydb_t *keydb); 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 volume_entry_t* keydb_get_volume_by_name(struct host_entry_t *host, const char *devmapper_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_volume_index(const struct host_entry_t *host, const struct volume_entry_t *volume);
struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name); struct host_entry_t* keydb_get_host_by_name(struct keydb_t *keydb, const char *host_name);
const struct host_entry_t* keydb_get_host_by_uuid(const struct keydb_t *keydb, const uint8_t uuid[static 16]); 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_add_host(struct keydb_t **keydb, const char *host_name);

View File

@ -1,6 +1,8 @@
import argparse import argparse
parser = argparse.ArgumentParser(prog = "luksrku client", description = "Connects to a luksrku key server and unlocks local LUKS volumes.", add_help = False) 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("-p", "--port", metavar = "port", default = 23170, help = "Port that is used for both UDP and TCP communication. Defaults to %(default)d.") 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.") parser.add_argument("-v", "--verbose", action = "count", default = 0, help = "Increase verbosity. Can be specified multiple times.")
parser.add_argument("filename", metavar = "filename", help = "Exported database file to load TLS-PSKs and list of disks from.") parser.add_argument("filename", metavar = "filename", help = "Exported database file to load TLS-PSKs and list of disks from.")
parser.add_argument("hostname", metavar = "hostname", nargs = "?", help = "When hostname is given, auto-searching for suitable servers is disabled and only a connection to the given hostname is attempted.") parser.add_argument("hostname", metavar = "hostname", nargs = "?", help = "When hostname is given, auto-searching for suitable servers is disabled and only a connection to the given hostname is attempted.")

View File

@ -97,6 +97,14 @@ static bool client_callback(enum argparse_client_option_t option, const char *va
pgmopts_rw.client.port = atoi(value); pgmopts_rw.client.port = atoi(value);
break; break;
case ARG_CLIENT_TIMEOUT:
pgmopts_rw.client.timeout_seconds = atoi(value);
break;
case ARG_CLIENT_NO_LUKS:
pgmopts_rw.client.no_luks = true;
break;
case ARG_CLIENT_VERBOSE: case ARG_CLIENT_VERBOSE:
pgmopts_rw.client.verbosity++; pgmopts_rw.client.verbosity++;
break; break;

View File

@ -48,6 +48,8 @@ struct pgmopts_client_t {
const char *filename; const char *filename;
const char *hostname; const char *hostname;
unsigned int port; unsigned int port;
unsigned int timeout_seconds;
bool no_luks;
unsigned int verbosity; unsigned int verbosity;
}; };

View File

@ -176,7 +176,7 @@ static void udp_handler_thread(void *vctx) {
while (true) { while (true) {
struct udp_query_t rx_msg; struct udp_query_t rx_msg;
struct sockaddr_in origin; struct sockaddr_in origin;
if (!wait_udp_query(client->udp_sd, client->port, &rx_msg, &origin, 1000)) { if (!wait_udp_query(client->udp_sd, &rx_msg, &origin)) {
continue; continue;
} }
@ -240,7 +240,7 @@ bool keyserver_start(const struct pgmopts_server_t *opts) {
} }
if (opts->answer_udp_queries) { if (opts->answer_udp_queries) {
keyserver.udp_sd = create_udp_socket(opts->port, false); keyserver.udp_sd = create_udp_socket(opts->port, false, 1000);
if (keyserver.udp_sd == -1) { if (keyserver.udp_sd == -1) {
success = false; success = false;
break; break;

31
udp.c
View File

@ -27,12 +27,13 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "log.h" #include "log.h"
#include "udp.h" #include "udp.h"
int create_udp_socket(unsigned int listen_port, bool send_broadcast) { int create_udp_socket(unsigned int listen_port, bool send_broadcast, unsigned int rx_timeout_millis) {
int sd = socket(AF_INET, SOCK_DGRAM, 0); int sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0) { if (sd < 0) {
log_libc(LLVL_ERROR, "Unable to create UDP server socket(2)"); log_libc(LLVL_ERROR, "Unable to create UDP server socket(2)");
@ -59,10 +60,21 @@ int create_udp_socket(unsigned int listen_port, bool send_broadcast) {
return -1; return -1;
} }
} }
if (rx_timeout_millis) {
struct timeval tv = {
.tv_sec = rx_timeout_millis / 1000,
.tv_usec = (rx_timeout_millis % 1000) * 1000,
};
if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
log_libc(LLVL_ERROR, "Unable to set UDP receive timeout to %u ms.", rx_timeout_millis);
close(sd);
return -1;
}
}
return sd; return sd;
} }
bool wait_udp_message(int sd, int port, void *data, unsigned int length, struct sockaddr_in *source, unsigned int timeout_millis) { bool wait_udp_message(int sd, void *data, unsigned int length, struct sockaddr_in *source) {
fprintf(stderr, "RECV...\n"); fprintf(stderr, "RECV...\n");
socklen_t socklen = sizeof(struct sockaddr_in); socklen_t socklen = sizeof(struct sockaddr_in);
ssize_t rx_bytes = recvfrom(sd,data, length, 0, (struct sockaddr*)source, &socklen); ssize_t rx_bytes = recvfrom(sd,data, length, 0, (struct sockaddr*)source, &socklen);
@ -92,8 +104,8 @@ bool send_udp_broadcast_message(int sd, int port, const void *data, unsigned int
return send_udp_message(sd, &destination, data, length, false); return send_udp_message(sd, &destination, data, length, false);
} }
bool wait_udp_query(int sd, int port, struct udp_query_t *query, struct sockaddr_in *source, unsigned int timeout_millis) { bool wait_udp_query(int sd, struct udp_query_t *query, struct sockaddr_in *source) {
bool rx_successful = wait_udp_message(sd, port, query, sizeof(struct udp_query_t), source, timeout_millis); bool rx_successful = wait_udp_message(sd, query, sizeof(struct udp_query_t), source);
if (rx_successful) { if (rx_successful) {
/* Also check if the message contains the correct magic */ /* Also check if the message contains the correct magic */
if (!memcmp(query->magic, UDP_MESSAGE_MAGIC, UDP_MESSAGE_MAGIC_SIZE)) { if (!memcmp(query->magic, UDP_MESSAGE_MAGIC, UDP_MESSAGE_MAGIC_SIZE)) {
@ -102,3 +114,14 @@ bool wait_udp_query(int sd, int port, struct udp_query_t *query, struct sockaddr
} }
return false; return false;
} }
bool wait_udp_response(int sd, struct udp_response_t *response, struct sockaddr_in *source) {
bool rx_successful = wait_udp_message(sd, response, sizeof(struct udp_response_t), source);
if (rx_successful) {
/* Also check if the message contains the correct magic */
if (!memcmp(response->magic, UDP_MESSAGE_MAGIC, UDP_MESSAGE_MAGIC_SIZE)) {
return true;
}
}
return false;
}

7
udp.h
View File

@ -28,11 +28,12 @@
#include "msg.h" #include "msg.h"
/*************** AUTO GENERATED SECTION FOLLOWS ***************/ /*************** AUTO GENERATED SECTION FOLLOWS ***************/
int create_udp_socket(unsigned int listen_port, bool send_broadcast); int create_udp_socket(unsigned int listen_port, bool send_broadcast, unsigned int rx_timeout_millis);
bool wait_udp_message(int sd, int port, void *data, unsigned int length, struct sockaddr_in *source, unsigned int timeout_millis); bool wait_udp_message(int sd, void *data, unsigned int length, struct sockaddr_in *source);
bool send_udp_message(int sd, struct sockaddr_in *destination, const void *data, unsigned int length, bool is_response); bool send_udp_message(int sd, struct sockaddr_in *destination, const void *data, unsigned int length, bool is_response);
bool send_udp_broadcast_message(int sd, int port, const void *data, unsigned int length); bool send_udp_broadcast_message(int sd, int port, const void *data, unsigned int length);
bool wait_udp_query(int sd, int port, struct udp_query_t *query, struct sockaddr_in *source, unsigned int timeout_millis); bool wait_udp_query(int sd, struct udp_query_t *query, struct sockaddr_in *source);
bool wait_udp_response(int sd, struct udp_response_t *response, struct sockaddr_in *source);
/*************** AUTO GENERATED SECTION ENDS ***************/ /*************** AUTO GENERATED SECTION ENDS ***************/
#endif #endif

9
util.c
View File

@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "util.h" #include "util.h"
@ -211,3 +212,11 @@ bool ascii_encode(char *dest, unsigned int dest_buffer_size, const uint8_t *sour
*dest = 0; *dest = 0;
return true; return true;
} }
double now(void) {
struct timeval tv;
if (gettimeofday(&tv, NULL)) {
return 0;
}
return tv.tv_sec + (tv.tv_usec * 1e-6);
}

1
util.h
View File

@ -43,6 +43,7 @@ bool buffer_randomize(uint8_t *buffer, unsigned int length);
bool is_zero(const void *data, unsigned int length); bool is_zero(const void *data, unsigned int length);
bool array_remove(void *base, unsigned int element_size, unsigned int element_count, unsigned int remove_element_index); bool array_remove(void *base, unsigned int element_size, unsigned int element_count, unsigned int remove_element_index);
bool ascii_encode(char *dest, unsigned int dest_buffer_size, const uint8_t *source_data, unsigned int source_data_length); bool ascii_encode(char *dest, unsigned int dest_buffer_size, const uint8_t *source_data, unsigned int source_data_length);
double now(void);
/*************** AUTO GENERATED SECTION ENDS ***************/ /*************** AUTO GENERATED SECTION ENDS ***************/
#endif #endif