kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 6ba7390cc9fcb19ec344b77a6d1b8f5c970785cf
parent 27da1dd7417bf81f7aa314e0d9110e4e8b7d7323
Author: Joris Vink <joris@coders.se>
Date:   Mon, 27 Feb 2017 20:58:04 -0800

Add rand_file configuration option for keymgr.

This option allows the user to specify a file to be used for
seeding the PRNG initially and to write random bytes at exit.

The option is only available if kore has TLS enabled (by default).

If you enable this option Kore will refuse to start if there is
a problem with the file specified (not found, not a file, invalid size, etc).

While here let the keymgr process call RAND_poll() every half hour
to grab more system entropy and seed it into the PRNG.

Diffstat:
conf/kore.conf.example | 11+++++++++++
includes/kore.h | 1+
src/config.c | 13+++++++++++++
src/keymgr.c | 125++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 149 insertions(+), 1 deletion(-)

diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -55,6 +55,17 @@ workers 4 # Store the pid of the main process in this file. #pidfile kore.pid +# If TLS is enabled you can specify a file where Kore will read +# initial entropy from and save entropy towards when exiting. +# +# Note that if you enable this you must provide the first iteration +# of this file by generating 1024 cryptographically safe random bytes +# and writing them to the file specified. +# +# Kore will refuse to start if the specified file does not exist, +# is of the wrong size or cannot be opened in anyway. +#rand_file random.data + # HTTP specific settings. # http_header_max Maximum size of HTTP headers (in bytes). # diff --git a/includes/kore.h b/includes/kore.h @@ -457,6 +457,7 @@ extern int tls_version; #if !defined(KORE_NO_TLS) extern DH *tls_dhparam; +extern char *rand_file; #endif extern u_int8_t nlisteners; diff --git a/src/config.c b/src/config.c @@ -64,6 +64,7 @@ static int configure_set_affinity(char *); static int configure_socket_backlog(char *); #if !defined(KORE_NO_TLS) +static int configure_rand_file(char *); static int configure_certfile(char *); static int configure_certkey(char *); static int configure_tls_version(char *); @@ -135,6 +136,7 @@ static struct { { "tls_version", configure_tls_version }, { "tls_cipher", configure_tls_cipher }, { "tls_dhparam", configure_tls_dhparam }, + { "rand_file", configure_rand_file }, { "certfile", configure_certfile }, { "certkey", configure_certkey }, { "client_certificates", configure_client_certificates }, @@ -453,6 +455,17 @@ configure_client_certificates(char *options) } static int +configure_rand_file(char *path) +{ + if (rand_file != NULL) + kore_free(rand_file); + + rand_file = kore_strdup(path); + + return (KORE_RESULT_OK); +} + +static int configure_certfile(char *path) { if (current_domain == NULL) { diff --git a/src/keymgr.c b/src/keymgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Joris Vink <joris@coders.se> + * Copyright (c) 2016-2017 Joris Vink <joris@coders.se> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,9 +15,12 @@ */ #include <sys/param.h> +#include <sys/stat.h> #include <openssl/evp.h> +#include <openssl/rand.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> @@ -26,16 +29,26 @@ #include "kore.h" #if !defined(KORE_NO_TLS) + +#define RAND_TMP_FILE "rnd.tmp" +#define RAND_POLL_INTERVAL (1800 * 1000) +#define RAND_FILE_SIZE 1024 + struct key { EVP_PKEY *pkey; struct kore_domain *dom; TAILQ_ENTRY(key) list; }; +char *rand_file = NULL; + static TAILQ_HEAD(, key) keys; extern volatile sig_atomic_t sig_recv; static int initialized = 0; +static void keymgr_load_randfile(void); +static void keymgr_save_randfile(void); + static void keymgr_load_privatekey(struct kore_domain *); static void keymgr_msg_recv(struct kore_msg *, const void *); @@ -48,6 +61,13 @@ void kore_keymgr_run(void) { int quit; + u_int64_t now, last_seed; + + if (rand_file != NULL) { + keymgr_load_randfile(); + } else { + kore_log(LOG_WARNING, "no rand_file location specified"); + } quit = 0; initialized = 1; @@ -66,9 +86,16 @@ kore_keymgr_run(void) kore_msg_worker_init(); kore_msg_register(KORE_MSG_KEYMGR_REQ, keymgr_msg_recv); + last_seed = 0; kore_log(LOG_NOTICE, "key manager started"); while (quit != 1) { + now = kore_time_ms(); + if ((now - last_seed) > RAND_POLL_INTERVAL) { + RAND_poll(); + last_seed = now; + } + if (sig_recv != 0) { switch (sig_recv) { case SIGQUIT: @@ -102,6 +129,8 @@ kore_keymgr_cleanup(void) if (initialized == 0) return; + keymgr_save_randfile(); + for (key = TAILQ_FIRST(&keys); key != NULL; key = next) { next = TAILQ_NEXT(key, list); TAILQ_REMOVE(&keys, key, list); @@ -112,6 +141,100 @@ kore_keymgr_cleanup(void) } static void +keymgr_load_randfile(void) +{ + int fd; + struct stat st; + ssize_t ret; + size_t total; + u_int8_t buf[RAND_FILE_SIZE]; + + if (rand_file == NULL) + return; + + if ((fd = open(rand_file, O_RDONLY)) == -1) + fatal("open(%s): %s", rand_file, errno_s); + + if (fstat(fd, &st) == -1) + fatal("stat(%s): %s", rand_file, errno_s); + if (!S_ISREG(st.st_mode)) + fatal("%s is not a file", rand_file); + if (st.st_size != RAND_FILE_SIZE) + fatal("%s has an invalid size", rand_file); + + total = 0; + + while (total != RAND_FILE_SIZE) { + ret = read(fd, buf, sizeof(buf)); + if (ret == 0) + fatal("EOF on %s", rand_file); + + if (ret == -1) { + if (errno == EINTR) + continue; + fatal("read(%s): %s", rand_file, errno_s); + } + + total += (size_t)ret; + RAND_seed(buf, (int)ret); + } + + (void)close(fd); + if (unlink(rand_file) == -1) { + kore_log(LOG_WARNING, "failed to unlink %s: %s", + rand_file, errno_s); + } +} + +static void +keymgr_save_randfile(void) +{ + int fd; + struct stat st; + ssize_t ret; + u_int8_t buf[RAND_FILE_SIZE]; + + if (rand_file == NULL) + return; + + if (stat(RAND_TMP_FILE, &st) != -1) { + kore_log(LOG_WARNING, "removing stale %s file", RAND_TMP_FILE); + (void)unlink(RAND_TMP_FILE); + } + + if (RAND_bytes(buf, sizeof(buf)) != 1) { + kore_log(LOG_WARNING, "RAND_bytes: %s", ssl_errno_s); + return; + } + + if ((fd = open(RAND_TMP_FILE, + O_CREAT | O_TRUNC | O_WRONLY, 0400)) == -1) { + kore_log(LOG_WARNING, + "failed to open %s: %s - random data not written", + RAND_TMP_FILE, errno_s); + return; + } + + ret = write(fd, buf, sizeof(buf)); + if (ret == -1 || (size_t)ret != sizeof(buf)) { + kore_log(LOG_WARNING, "failed to write random data"); + (void)close(fd); + (void)unlink(RAND_TMP_FILE); + return; + } + + if (close(fd) == -1) + kore_log(LOG_WARNING, "close(%s): %s", RAND_TMP_FILE, errno_s); + + if (rename(RAND_TMP_FILE, rand_file) == -1) { + kore_log(LOG_WARNING, "rename(%s, %s): %s", + RAND_TMP_FILE, rand_file, errno_s); + (void)unlink(rand_file); + (void)unlink(RAND_TMP_FILE); + } +} + +static void keymgr_load_privatekey(struct kore_domain *dom) { FILE *fp;