Further work on the client code

Trying to get everything in shape, not looking too bad.
This commit is contained in:
Johannes Bauer 2019-10-23 21:13:50 +02:00
parent 425e2dcd66
commit 983217ffbd
3 changed files with 230 additions and 83 deletions

View File

@ -1,10 +1,10 @@
.PHONY: all clean test testclient install parsers .PHONY: all clean test_s test_c install parsers
all: luksrku all: luksrku
BUILD_REVISION := $(shell git describe --abbrev=10 --dirty --always --tags) BUILD_REVISION := $(shell git describe --abbrev=10 --dirty --always --tags)
INSTALL_PREFIX := /usr/local/ 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 := -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_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"' 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 += `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 PYPGMOPTS := ../Python/pypgmopts/pypgmopts
@ -26,14 +26,11 @@ install: all
clean: clean:
rm -f $(OBJS) $(OBJS_CFG) luksrku rm -f $(OBJS) $(OBJS_CFG) luksrku
test: luksrku test_s: luksrku
./luksrku server -vv base ./luksrku server -vv base
gdb: luksrku test_c: luksrku
gdb --args ./luksrku -v --server-mode -k server_key.bin ./luksrku client -vv export 127.0.0.1
testclient: luksrku
./luksrku -v --client-mode -k client_keys.bin
.c.o: .c.o:
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<

143
client.c
View File

@ -29,6 +29,10 @@
#include <unistd.h> #include <unistd.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "log.h" #include "log.h"
#include "openssl.h" #include "openssl.h"
@ -36,6 +40,7 @@
#include "msg.h" #include "msg.h"
#include "client.h" #include "client.h"
#include "blacklist.h" #include "blacklist.h"
#include "keydb.h"
#if 0 #if 0
static const struct keydb_t *client_keydb; static const struct keydb_t *client_keydb;
@ -207,6 +212,142 @@ static bool tls_client(const struct keydb_t *keydb, const struct options_t *opti
} }
#endif #endif
bool keyclient_start(const struct pgmopts_client_t *opts) { struct keyclient_t {
const struct pgmopts_client_t *opts;
struct keydb_t *keydb;
bool volume_unlocked[MAX_VOLUMES_PER_HOST];
};
static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sess) {
fprintf(stderr, "CLIENT CALLBACK\n");
return 0;
}
static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) {
struct generic_tls_ctx_t gctx;
if (!create_generic_tls_context(&gctx, false)) {
log_msg(LLVL_FATAL, "Failed to create OpenSSL client context.");
return false;
}
SSL_CTX_set_psk_use_session_callback(gctx.ctx, psk_client_callback);
SSL *ssl = SSL_new(gctx.ctx);
if (ssl) {
SSL_set_fd(ssl, sd);
SSL_set_app_data(ssl, keyclient);
if (SSL_connect(ssl) == 1) {
fprintf(stderr, "OK\n");
} else {
log_openssl(LLVL_FATAL, "SSL_connect failed");
}
} else {
log_openssl(LLVL_FATAL, "Cannot establish SSL context when trying to connect to server");
}
SSL_free(ssl);
free_generic_tls_context(&gctx);
return true; return true;
} }
static bool contact_keyserver_ipv4(struct keyclient_t *keyclient, struct sockaddr_in *sockaddr_in, unsigned int port) {
sockaddr_in->sin_port = htons(port);
int sd = socket(sockaddr_in->sin_family, SOCK_STREAM, 0);
if (sd == -1) {
log_libc(LLVL_ERROR, "Failed to create socket(3)");
return false;
}
if (connect(sd, (struct sockaddr*)sockaddr_in, sizeof(struct sockaddr_in)) == -1) {
log_libc(LLVL_ERROR, "Failed to connect(3) to %d.%d.%d.%d:%d", PRINTF_FORMAT_IP(sockaddr_in), port);
close(sd);
return false;
}
bool success = contact_keyserver_socket(keyclient, sd);
shutdown(sd, SHUT_RDWR);
close(sd);
return success;
}
static bool contact_keyserver_hostname(struct keyclient_t *keyclient, const char *hostname) {
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *result;
int resolve_result = getaddrinfo(hostname, NULL, &hints, &result);
if (resolve_result) {
log_msg(LLVL_ERROR, "Failed to resolve hostname %s using getaddrinfo(3): %s", hostname, gai_strerror(resolve_result));
return false;
}
if (result->ai_addr->sa_family != AF_INET) {
freeaddrinfo(result);
log_msg(LLVL_ERROR, "getaddrinfo(3) returned non-IPv4 entry");
return false;
}
struct sockaddr_in *sin_address = (struct sockaddr_in*)result->ai_addr;
log_msg(LLVL_DEBUG, "Resolved %s to %d.%d.%d.%d", hostname, PRINTF_FORMAT_IP(sin_address));
bool success = contact_keyserver_ipv4(keyclient, sin_address, keyclient->opts->port);
freeaddrinfo(result);
return success;
}
bool keyclient_start(const struct pgmopts_client_t *opts) {
/* Load key database first */
struct keyclient_t keyclient = {
.opts = opts,
};
bool success = true;
do {
keyclient.keydb = keydb_read(opts->filename);
if (!keyclient.keydb) {
log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename);
success = false;
break;
}
if (keyclient.keydb->server_database) {
log_msg(LLVL_FATAL, "Not an exported key database: %s -- this database contains LUKS passphrases, refusing to work with it!", opts->filename);
success = false;
break;
}
if (keyclient.keydb->host_count != 1) {
log_msg(LLVL_FATAL, "Host count %d in %s -- expected exactly one host entry for an exported database.", keyclient.keydb->host_count, opts->filename);
success = false;
break;
}
struct 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;
break;
}
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);
success = false;
break;
}
} else {
/* TODO: Loop until keyserver found */
}
} while (false);
if (keyclient.keydb) {
keydb_free(keyclient.keydb);
}
return success;
}

157
server.c
View File

@ -330,92 +330,101 @@ static void client_handler_thread(void *vctx) {
struct client_ctx_t *client = (struct client_ctx_t*)vctx; struct client_ctx_t *client = (struct client_ctx_t*)vctx;
SSL *ssl = SSL_new(client->gctx->ctx); SSL *ssl = SSL_new(client->gctx->ctx);
SSL_set_fd(ssl, client->fd); if (ssl) {
SSL_set_app_data(ssl, client); SSL_set_fd(ssl, client->fd);
SSL_set_app_data(ssl, client);
if (SSL_accept(ssl) <= 0) { if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
} else {
if (client->host) {
log_msg(LLVL_DEBUG, "Client \"%s\" connected, sending unlock data for %d volumes.", client->host->host_name, 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];
struct msg_t msg = { 0 };
memcpy(msg.volume_uuid, volume->volume_uuid, 16);
memcpy(msg.luks_passphrase_raw, volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES);
int txlen = SSL_write(ssl, &msg, sizeof(msg));
OPENSSL_cleanse(&msg, sizeof(msg));
if (txlen != sizeof(msg)) {
log_msg(LLVL_WARNING, "Tried to send message of %d bytes, but sent %d. Severing connection to client.", sizeof(msg), txlen);
break;
}
}
} else { } else {
log_msg(LLVL_FATAL, "Client connected, but no host set."); if (client->host) {
} log_msg(LLVL_DEBUG, "Client \"%s\" connected, sending unlock data for %d volumes.", client->host->host_name, 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];
struct msg_t msg = { 0 };
memcpy(msg.volume_uuid, volume->volume_uuid, 16);
memcpy(msg.luks_passphrase_raw, volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES);
int txlen = SSL_write(ssl, &msg, sizeof(msg));
OPENSSL_cleanse(&msg, sizeof(msg));
if (txlen != sizeof(msg)) {
log_msg(LLVL_WARNING, "Tried to send message of %d bytes, but sent %d. Severing connection to client.", sizeof(msg), txlen);
break;
}
}
} else {
log_msg(LLVL_FATAL, "Client connected, but no host set.");
}
}
} else {
log_openssl(LLVL_FATAL, "Cannot establish SSL context for connecting client");
}
SSL_free(ssl); SSL_free(ssl);
shutdown(client->fd, SHUT_RDWR); shutdown(client->fd, SHUT_RDWR);
close(client->fd); close(client->fd);
} }
bool keyserver_start(const struct pgmopts_server_t *opts) { bool keyserver_start(const struct pgmopts_server_t *opts) {
/* Load key database first */ bool success = true;
struct keydb_t* keydb = keydb_read(opts->filename); struct keydb_t* keydb = NULL;
if (!keydb) { struct generic_tls_ctx_t gctx = { 0 };
log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename); do {
return false; /* Load key database first */
} keydb = keydb_read(opts->filename);
if (!keydb) {
if (!keydb->server_database) { log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename);
log_msg(LLVL_FATAL, "Not a server key database: %s", opts->filename); success = false;
keydb_free(keydb); break;
return false;
}
struct generic_tls_ctx_t gctx;
if (!create_generic_tls_context(&gctx, true)) {
log_msg(LLVL_FATAL, "Failed to create OpenSSL server context.");
return false;
}
SSL_CTX_set_psk_find_session_callback(gctx.ctx, psk_server_callback);
int tcp_sock = create_tcp_server_socket(opts->port);
if (tcp_sock == -1) {
log_msg(LLVL_ERROR, "Cannot start server without server socket.");
free_generic_tls_context(&gctx);
return false;
}
while (true) {
struct sockaddr_in addr;
unsigned int len = sizeof(addr);
int client = accept(tcp_sock, (struct sockaddr*)&addr, &len);
if (client < 0) {
log_libc(LLVL_ERROR, "Unable to accept(2)");
close(tcp_sock);
free_generic_tls_context(&gctx);
return false;
} }
/* Client has connected, fire up client thread. */ if (!keydb->server_database) {
struct client_ctx_t client_ctx = { log_msg(LLVL_FATAL, "Not a server key database: %s", opts->filename);
.gctx = &gctx, success = false;
.keydb = keydb, break;
.fd = client,
};
if (!pthread_create_detached_thread(client_handler_thread, &client_ctx, sizeof(client_ctx))) {
log_libc(LLVL_FATAL, "Unable to pthread_attr_init(3)");
close(tcp_sock);
free_generic_tls_context(&gctx);
return false;
} }
}
if (!create_generic_tls_context(&gctx, true)) {
log_msg(LLVL_FATAL, "Failed to create OpenSSL server context.");
success = false;
break;
}
SSL_CTX_set_psk_find_session_callback(gctx.ctx, psk_server_callback);
int tcp_sock = create_tcp_server_socket(opts->port);
if (tcp_sock == -1) {
log_msg(LLVL_ERROR, "Cannot start server without server socket.");
success = false;
break;
}
while (true) {
struct sockaddr_in addr;
unsigned int len = sizeof(addr);
int client = accept(tcp_sock, (struct sockaddr*)&addr, &len);
if (client < 0) {
log_libc(LLVL_ERROR, "Unable to accept(2)");
close(tcp_sock);
free_generic_tls_context(&gctx);
return false;
}
/* Client has connected, fire up client thread. */
struct client_ctx_t client_ctx = {
.gctx = &gctx,
.keydb = keydb,
.fd = client,
};
if (!pthread_create_detached_thread(client_handler_thread, &client_ctx, sizeof(client_ctx))) {
log_libc(LLVL_FATAL, "Unable to pthread_attr_init(3)");
close(tcp_sock);
free_generic_tls_context(&gctx);
return false;
}
}
} while (false);
free_generic_tls_context(&gctx); free_generic_tls_context(&gctx);
return true; keydb_free(keydb);
return success;
} }