Unlocking LUKS volumes works
First complete technical round-trip complete, can unlock the LUKS volumes described in the server/client databases successfully.
This commit is contained in:
parent
849e3a5949
commit
3478fa4555
7
Makefile
7
Makefile
@ -10,6 +10,7 @@ CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak
|
||||
PYPGMOPTS := ../Python/pypgmopts/pypgmopts
|
||||
|
||||
LDFLAGS := `pkg-config --libs openssl`
|
||||
TEST_PREFIX := local
|
||||
|
||||
OBJS := \
|
||||
argparse_client.o \
|
||||
@ -18,9 +19,11 @@ OBJS := \
|
||||
blacklist.o \
|
||||
client.o \
|
||||
editor.o \
|
||||
exec.o \
|
||||
file_encryption.o \
|
||||
keydb.o \
|
||||
log.o \
|
||||
luks.o \
|
||||
luksrku.o \
|
||||
openssl.o \
|
||||
pgmopts.o \
|
||||
@ -45,10 +48,10 @@ clean:
|
||||
rm -f $(OBJS) $(OBJS_CFG) luksrku
|
||||
|
||||
test_s: luksrku
|
||||
./luksrku server -vv testdata/server.bin
|
||||
./luksrku server -vv testdata/$(TEST_PREFIX)_server.bin
|
||||
|
||||
test_c: luksrku
|
||||
./luksrku client -vv --no-luks testdata/client.bin
|
||||
./luksrku client -vv --no-luks testdata/$(TEST_PREFIX)_client.bin
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
@ -31,14 +31,14 @@
|
||||
static struct blacklist_entry_t blacklist[BLACKLIST_ENTRY_COUNT];
|
||||
|
||||
static bool blacklist_entry_expired(int index) {
|
||||
return now() > blacklist[index].entered + BLACKLIST_ENTRY_TIMEOUT_SECS;
|
||||
return now() > blacklist[index].timeout;
|
||||
}
|
||||
|
||||
void blacklist_ip(uint32_t ip) {
|
||||
void blacklist_ip(uint32_t ip, unsigned int timeout_seconds) {
|
||||
for (int i = 0; i < BLACKLIST_ENTRY_COUNT; i++) {
|
||||
if (blacklist_entry_expired(i)) {
|
||||
blacklist[i].ip = ip;
|
||||
blacklist[i].entered = now();
|
||||
blacklist[i].timeout = now() + timeout_seconds;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -28,15 +28,14 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BLACKLIST_ENTRY_COUNT 32
|
||||
#define BLACKLIST_ENTRY_TIMEOUT_SECS 15
|
||||
|
||||
struct blacklist_entry_t {
|
||||
uint32_t ip;
|
||||
double entered;
|
||||
double timeout;
|
||||
};
|
||||
|
||||
/*************** AUTO GENERATED SECTION FOLLOWS ***************/
|
||||
void blacklist_ip(uint32_t ip);
|
||||
void blacklist_ip(uint32_t ip, unsigned int timeout_seconds);
|
||||
bool is_ip_blacklisted(uint32_t ip);
|
||||
/*************** AUTO GENERATED SECTION ENDS ***************/
|
||||
|
||||
|
71
client.c
71
client.c
@ -43,6 +43,7 @@
|
||||
#include "keydb.h"
|
||||
#include "uuid.h"
|
||||
#include "udp.h"
|
||||
#include "luks.h"
|
||||
|
||||
struct keyclient_t {
|
||||
const struct pgmopts_client_t *opts;
|
||||
@ -60,17 +61,26 @@ 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 do_unlock_luks_volume(const struct volume_entry_t *volume, const struct msg_t *unlock_msg) {
|
||||
return true;
|
||||
static bool unlock_luks_volume(const struct 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_pw(volume->volume_uuid, volume->devmapper_name, luks_passphrase, strlen(luks_passphrase));
|
||||
} else {
|
||||
log_msg(LLVL_FATAL, "Failed to transcribe raw LUKS passphrase to text form.");
|
||||
success = false;
|
||||
}
|
||||
OPENSSL_cleanse(luks_passphrase, sizeof(luks_passphrase));
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool unlock_luks_volume(struct keyclient_t *keyclient, const struct msg_t *unlock_msg) {
|
||||
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);
|
||||
char volume_uuid_str[ASCII_UUID_BUFSIZE];
|
||||
sprintf_uuid(volume_uuid_str, 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);
|
||||
log_msg(LLVL_WARNING, "Keyserver provided key for unlocking volume UUID %s, but this volume is not known on the client side.", volume_uuid_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -80,7 +90,16 @@ static bool unlock_luks_volume(struct keyclient_t *keyclient, const struct msg_t
|
||||
if (keyclient->opts->no_luks) {
|
||||
keyclient->volume_unlocked[volume_index] = true;
|
||||
} else {
|
||||
keyclient->volume_unlocked[volume_index] = do_unlock_luks_volume(volume, unlock_msg);
|
||||
if (!keyclient->volume_unlocked[volume_index]) {
|
||||
bool success = unlock_luks_volume(volume, unlock_msg);
|
||||
keyclient->volume_unlocked[volume_index] = success;
|
||||
if (!success) {
|
||||
log_msg(LLVL_ERROR, "Unlocking of volume %s / %s failed with the server-provided passphrase.", volume->devmapper_name, volume_uuid_str);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
log_msg(LLVL_WARNING, "Volume %s / %s already unlocked, not attemping to unlock again.", volume->devmapper_name, volume_uuid_str);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_msg(LLVL_FATAL, "Error calculating volume offset for volume %p from base %p.", volume, host->volumes);
|
||||
@ -118,7 +137,7 @@ static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) {
|
||||
char uuid_str[ASCII_UUID_BUFSIZE];
|
||||
sprintf_uuid(uuid_str, msg.volume_uuid);
|
||||
log_msg(LLVL_TRACE, "Received LUKS key to unlock volume with UUID %s", uuid_str);
|
||||
if (unlock_luks_volume(keyclient, &msg)) {
|
||||
if (attempt_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);
|
||||
@ -187,14 +206,19 @@ static bool contact_keyserver_hostname(struct keyclient_t *keyclient, const char
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool all_volumes_unlocked(struct keyclient_t *keyclient) {
|
||||
static unsigned int locked_volume_count(struct keyclient_t *keyclient) {
|
||||
unsigned int count = 0;
|
||||
const unsigned int volume_count = keyclient->keydb->hosts[0].volume_count;
|
||||
for (unsigned int i = 0; i < volume_count; i++) {
|
||||
if (!keyclient->volume_unlocked[i]) {
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool all_volumes_unlocked(struct keyclient_t *keyclient) {
|
||||
return locked_volume_count(keyclient) == 0;
|
||||
}
|
||||
|
||||
static bool abort_searching_for_keyserver(struct keyclient_t *keyclient) {
|
||||
@ -206,7 +230,7 @@ static bool abort_searching_for_keyserver(struct keyclient_t *keyclient) {
|
||||
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);
|
||||
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));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -234,9 +258,14 @@ static bool broadcast_for_keyserver(struct keyclient_t *keyclient) {
|
||||
};
|
||||
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 (!is_ip_blacklisted(src.sin_addr.s_addr)) {
|
||||
log_msg(LLVL_INFO, "Keyserver found at %d.%d.%d.%d", PRINTF_FORMAT_IP(&src));
|
||||
blacklist_ip(src.sin_addr.s_addr, BLACKLIST_TIMEOUT_CLIENT);
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
log_msg(LLVL_DEBUG, "Potential keyserver at %d.%d.%d.%d ignored, blacklist in effect.", PRINTF_FORMAT_IP(&src));
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,10 +310,20 @@ bool keyclient_start(const struct pgmopts_client_t *opts) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Determine which of these volumes are already unlocked */
|
||||
for (unsigned int i = 0; i < host->volume_count; i++) {
|
||||
keyclient.volume_unlocked[i] = is_luks_device_opened(host->volumes[i].devmapper_name);
|
||||
}
|
||||
if (all_volumes_unlocked(&keyclient)) {
|
||||
log_msg(LLVL_INFO, "All %u volumes are unlocked already, not contacting luksrku key server.", host->volume_count);
|
||||
break;
|
||||
} else {
|
||||
log_msg(LLVL_DEBUG, "%u of %u volumes are currently locked.", locked_volume_count(&keyclient), host->volume_count);
|
||||
}
|
||||
|
||||
/* Transcribe the host UUID to ASCII so we only have to do this once */
|
||||
sprintf_uuid((char*)keyclient.identifier, host->host_uuid);
|
||||
|
||||
log_msg(LLVL_DEBUG, "Attempting to unlock %d volumes of host \"%s\".", host->volume_count, host->host_name);
|
||||
if (opts->hostname) {
|
||||
if (!contact_keyserver_hostname(&keyclient, opts->hostname)) {
|
||||
log_msg(LLVL_ERROR, "Failed to contact key server: %s", opts->hostname);
|
||||
|
4
global.h
4
global.h
@ -24,6 +24,10 @@
|
||||
#ifndef __GLOBAL_H__
|
||||
#define __GLOBAL_H__
|
||||
|
||||
/* Blacklisting timeouts in seconds */
|
||||
#define BLACKLIST_TIMEOUT_CLIENT 3600
|
||||
#define BLACKLIST_TIMEOUT_SERVER 15
|
||||
|
||||
/* Size in bytes of the PSK that is used for TLS */
|
||||
#define PSK_SIZE_BYTES 32
|
||||
|
||||
|
9
luks.c
9
luks.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
luksrku - Tool to remotely unlock LUKS disks using TLS.
|
||||
Copyright (C) 2016-2016 Johannes Bauer
|
||||
Copyright (C) 2016-2019 Johannes Bauer
|
||||
|
||||
This file is part of luksrku.
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include "log.h"
|
||||
#include "exec.h"
|
||||
#include "util.h"
|
||||
#include "uuid.h"
|
||||
|
||||
bool is_luks_device_opened(const char *mapping_name) {
|
||||
const char *command[] = {
|
||||
@ -42,7 +43,7 @@ bool is_luks_device_opened(const char *mapping_name) {
|
||||
mapping_name,
|
||||
NULL,
|
||||
};
|
||||
struct runresult_t runresult = exec_command(command, should_log(LLVL_DEBUG));
|
||||
struct runresult_t runresult = exec_command(command, should_log(LLVL_TRACE));
|
||||
return runresult.success && (runresult.returncode == 0);
|
||||
}
|
||||
|
||||
@ -86,7 +87,7 @@ static bool wipe_passphrase_file(const char *filename, int length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *write_passphrase_file(const uint8_t *passphrase, int passphrase_length) {
|
||||
static const char *write_passphrase_file(const void *passphrase, int passphrase_length) {
|
||||
//const char *filename = "/dev/shm/luksrku_passphrase.bin"; /* TODO make this variable */
|
||||
const char *filename = "/tmp/luksrku_passphrase.bin";
|
||||
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
@ -106,7 +107,7 @@ static const char *write_passphrase_file(const uint8_t *passphrase, int passphra
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool open_luks_device_pw(const uint8_t *encrypted_device_uuid, const char *mapping_name, const uint8_t *passphrase, int passphrase_length) {
|
||||
bool open_luks_device_pw(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length) {
|
||||
const char *pw_filename = write_passphrase_file(passphrase, passphrase_length);
|
||||
if (!pw_filename) {
|
||||
return false;
|
||||
|
2
luks.h
2
luks.h
@ -30,7 +30,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_file);
|
||||
bool open_luks_device_pw(const uint8_t *encrypted_device_uuid, const char *mapping_name, const uint8_t *passphrase, int passphrase_length);
|
||||
bool open_luks_device_pw(const uint8_t *encrypted_device_uuid, const char *mapping_name, const char *passphrase, unsigned int passphrase_length);
|
||||
/*************** AUTO GENERATED SECTION ENDS ***************/
|
||||
|
||||
#endif
|
||||
|
2
server.c
2
server.c
@ -187,7 +187,7 @@ static void udp_handler_thread(void *vctx) {
|
||||
if (is_ip_blacklisted(ipv4)) {
|
||||
continue;
|
||||
}
|
||||
blacklist_ip(ipv4);
|
||||
blacklist_ip(ipv4, BLACKLIST_TIMEOUT_SERVER);
|
||||
|
||||
/* Check if we have this host in our database */
|
||||
if (keydb_get_host_by_uuid(client->keydb, rx_msg.host_uuid)) {
|
||||
|
BIN
testdata/local_client.bin
vendored
Normal file
BIN
testdata/local_client.bin
vendored
Normal file
Binary file not shown.
BIN
testdata/local_server.bin
vendored
Normal file
BIN
testdata/local_server.bin
vendored
Normal file
Binary file not shown.
2
udp.c
2
udp.c
@ -75,10 +75,8 @@ int create_udp_socket(unsigned int listen_port, bool send_broadcast, unsigned in
|
||||
return sd;
|
||||
}
|
||||
bool wait_udp_message(int sd, void *data, unsigned int length, struct sockaddr_in *source) {
|
||||
fprintf(stderr, "RECV...\n");
|
||||
socklen_t socklen = sizeof(struct sockaddr_in);
|
||||
ssize_t rx_bytes = recvfrom(sd,data, length, 0, (struct sockaddr*)source, &socklen);
|
||||
fprintf(stderr, "RECV %ld\n", rx_bytes);
|
||||
return rx_bytes == length;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user