Allow on-the-fly reloading of certificates/keys.

This commit introduces the ability for the keymgr process
to reload the certificates/keys for domains when receiving
a SIGUSR1 signal.

The keymgr receives 2 new configuration options:
	- keymgr_root_path
		The root path where the keymgr will live.
		If -n is not specified when the application starts the
		keymgr process will chroot into here.

	- keymgr_runas_user
		The user the keymgr will drop privileges towards if
		-r was not specified.

All certfile and certkey configuration options are now relative to the
keymgr_root_path configuration setting.

The keymgr process will now also load the certificate for the domain
(rather then the workers) and submit these to the worker processes so
they can be reloaded when required.

Worker processes will refuse connections until the TLS configuration
for a given domain is completed (aka: the workers receive the certificate
for that domain).

Other changes:
	- client_certificates renamed to client_verify.
	- the chroot configuration option is now called root.
	- kore is a little more verbose if privsep options are missing.
	- filemaps are now relative to the root configuration option.
This commit is contained in:
Joris Vink 2018-07-11 09:44:29 +02:00
parent bf6c0e150f
commit cffb7ec379
12 changed files with 383 additions and 102 deletions

View File

@ -12,10 +12,15 @@
# Server configuration.
bind 127.0.0.1 443
# The path worker processes will chroot into after starting.
chroot /home/joris/src/kore
# The worker process root directory. If chrooting was not disabled
# at startup the worker processes will chroot into this directory.
#
# If this configuration option is not set, Kore will take the current
# working directory as the root.
root /home/joris/src/kore
# Worker processes will run as the specified user.
# Worker processes will run as the specified user. If this option is
# missing Kore will run as the current user.
runas joris
# How many worker processes Kore will spawn. If the directive
@ -68,6 +73,25 @@ workers 4
# NOTE: This file location must be inside your chrooted environment.
#rand_file random.data
# Key manager specific options.
# If TLS is enabled you will need to specify paths to the domain
# certificate and key that Kore will load. This loading is done
# from the keymgr (separate process) and all paths must be relative
# to the keymgr_root_path configuration option.
#
# keymgr_root_path The root path the keymgr will chdir into.
# If chroot was not disable at startup time
# the keymgr process will chroot into here.
#
# keymgr_runas_user The user to run the keymgr as.
#
# If privsep and chrooting is enabled at startup time but these
# configuration options were not set, they will take over the
# values from the 'root' and 'runas' configuration options.
#
#keymgr_root_path
#keymgr_runas_user
# Filemap settings
# filemap_index Name of the file to be used as the directory
# index for a filemap.
@ -203,9 +227,13 @@ authentication auth_example {
#
# accesslog
# - File where all requests are logged.
# client_certificates [CA] [optional CRL]
# - Require client certificates to be sent for the given
# CA with an optional CRL file.
#
# NOTE: due to current limitations the client_verify CA path
# MUST be in the 'root' of the Kore workers, not the keymgr.
#
# client_verify [CA] [optional CRL]
# - Turns on client verification, requiring the client to
# send a certificate that will be verified by the given CA.
# client_verify_depth [depth]
# - Configure the depth for x509 chain validation.
# By default 1.
@ -244,6 +272,9 @@ domain localhost {
# Allow access to files from the directory static_files via
# the /files/ URI.
#
# Note the directory given must be relative to the root configuration
# option.
filemap /files/ static_files
# Configure /params-test POST to only accept the following parameters.
@ -279,7 +310,7 @@ domain localhost {
# certfile cert/other/server.crt
# certkey cert/other/server.key
# accesslog /var/log/other_kore_access.log
# client_certificates cert/other/ca.crt
# client_verify /other/ca.crt
# client_verify_depth 1
# static /css/style.css serve_style_css

View File

@ -54,8 +54,8 @@ init(int state)
void
received_message(struct kore_msg *msg, const void *data)
{
kore_log(LOG_INFO, "got message from %u (%d bytes): %.*s", msg->src,
msg->length, msg->length, (const char *)data);
kore_log(LOG_INFO, "got message from %u (%zu bytes): %.*s", msg->src,
msg->length, (int)msg->length, (const char *)data);
}
/*

View File

@ -363,6 +363,7 @@ struct kore_worker {
int pipe[2];
struct connection *msg[2];
u_int8_t has_lock;
int restarted;
u_int64_t time_locked;
struct kore_module_handle *active_hdlr;
};
@ -446,13 +447,15 @@ struct kore_timer {
#define KORE_WORKER_KEYMGR 0
/* Reserved message ids, registered on workers. */
#define KORE_MSG_ACCESSLOG 1
#define KORE_MSG_WEBSOCKET 2
#define KORE_MSG_KEYMGR_REQ 3
#define KORE_MSG_KEYMGR_RESP 4
#define KORE_MSG_SHUTDOWN 5
#define KORE_MSG_ENTROPY_REQ 6
#define KORE_MSG_ENTROPY_RESP 7
#define KORE_MSG_ACCESSLOG 1
#define KORE_MSG_WEBSOCKET 2
#define KORE_MSG_KEYMGR_REQ 3
#define KORE_MSG_KEYMGR_RESP 4
#define KORE_MSG_SHUTDOWN 5
#define KORE_MSG_ENTROPY_REQ 6
#define KORE_MSG_ENTROPY_RESP 7
#define KORE_MSG_CERTIFICATE 8
#define KORE_MSG_CERTIFICATE_REQ 9
/* Predefined message targets. */
#define KORE_MSG_PARENT 1000
@ -462,17 +465,24 @@ struct kore_msg {
u_int8_t id;
u_int16_t src;
u_int16_t dst;
u_int32_t length;
size_t length;
};
#if !defined(KORE_NO_TLS)
struct kore_keyreq {
int padding;
char domain[KORE_DOMAINNAME_LEN];
u_int8_t domain_len;
u_int16_t domain_len;
u_int16_t data_len;
u_int8_t data[];
};
struct kore_x509_msg {
char domain[KORE_DOMAINNAME_LEN];
u_int16_t domain_len;
size_t data_len;
u_int8_t data[];
};
#endif
#if !defined(KORE_SINGLE_BINARY)
@ -483,16 +493,18 @@ extern pid_t kore_pid;
extern int foreground;
extern int kore_debug;
extern int skip_chroot;
extern char *chroot_path;
extern int skip_runas;
extern char *runas_user;
extern char *kore_pidfile;
extern char *kore_root_path;
extern char *kore_runas_user;
extern char *kore_tls_cipher_list;
extern int tls_version;
#if !defined(KORE_NO_TLS)
extern int tls_version;
extern DH *tls_dhparam;
extern char *rand_file;
extern char *keymgr_runas_user;
extern char *keymgr_root_path;
#endif
extern u_int8_t nlisteners;
@ -641,7 +653,7 @@ void kore_msg_worker_init(void);
void kore_msg_parent_init(void);
void kore_msg_parent_add(struct kore_worker *);
void kore_msg_parent_remove(struct kore_worker *);
void kore_msg_send(u_int16_t, u_int8_t, const void *, u_int32_t);
void kore_msg_send(u_int16_t, u_int8_t, const void *, size_t);
int kore_msg_register(u_int8_t,
void (*cb)(struct kore_msg *, const void *));
@ -672,9 +684,9 @@ void kore_domain_closelogs(void);
void *kore_module_getsym(const char *, struct kore_runtime **);
void kore_domain_load_crl(void);
void kore_domain_keymgr_init(void);
void kore_domain_tlsinit(struct kore_domain *);
void kore_module_load(const char *, const char *, int);
void kore_domain_callback(void (*cb)(struct kore_domain *));
void kore_domain_tlsinit(struct kore_domain *, const void *, size_t);
int kore_module_handler_new(const char *, const char *,
const char *, const char *, int);
void kore_module_handler_free(struct kore_module_handle *);
@ -757,7 +769,7 @@ void kore_buf_appendv(struct kore_buf *, const char *, va_list);
void kore_buf_replace_string(struct kore_buf *, char *, void *, size_t);
void kore_keymgr_run(void);
void kore_keymgr_cleanup(void);
void kore_keymgr_cleanup(int);
void kore_worker_configure(void);
void kore_parent_configure(int, char **);

View File

@ -53,7 +53,7 @@ extern u_int32_t asset_len_builtin_kore_conf;
static int configure_include(char *);
static int configure_bind(char *);
static int configure_domain(char *);
static int configure_chroot(char *);
static int configure_root(char *);
static int configure_runas(char *);
static int configure_workers(char *);
static int configure_pidfile(char *);
@ -70,8 +70,10 @@ static int configure_certkey(char *);
static int configure_tls_version(char *);
static int configure_tls_cipher(char *);
static int configure_tls_dhparam(char *);
static int configure_keymgr_root(char *);
static int configure_keymgr_runas(char *);
static int configure_client_verify(char *);
static int configure_client_verify_depth(char *);
static int configure_client_certificates(char *);
#endif
#if !defined(KORE_NO_HTTP)
@ -117,8 +119,6 @@ static int configure_python_path(char *);
static int configure_python_import(char *);
#endif
static void domain_tls_init(void);
static struct {
const char *name;
int (*configure)(char *);
@ -130,8 +130,9 @@ static struct {
{ "python_path", configure_python_path },
{ "python_import", configure_python_import },
#endif
{ "root", configure_root },
{ "chroot", configure_root },
{ "domain", configure_domain },
{ "chroot", configure_chroot },
{ "runas", configure_runas },
{ "workers", configure_workers },
{ "worker_max_connections", configure_max_connections },
@ -145,9 +146,11 @@ static struct {
{ "tls_cipher", configure_tls_cipher },
{ "tls_dhparam", configure_tls_dhparam },
{ "rand_file", configure_rand_file },
{ "keymgr_runas", configure_keymgr_runas },
{ "keymgr_root", configure_keymgr_root },
{ "certfile", configure_certfile },
{ "certkey", configure_certkey },
{ "client_certificates", configure_client_certificates },
{ "client_verify", configure_client_verify },
{ "client_verify_depth", configure_client_verify_depth },
#endif
#if !defined(KORE_NO_HTTP)
@ -205,6 +208,7 @@ void
kore_parse_config(void)
{
FILE *fp;
char path[PATH_MAX];
#if !defined(KORE_SINGLE_BINARY)
if ((fp = fopen(config_file, "r")) == NULL)
@ -219,21 +223,48 @@ kore_parse_config(void)
if (!kore_module_loaded())
fatal("no application module was loaded");
if (skip_chroot != 1 && chroot_path == NULL) {
fatal("missing a chroot path");
if (kore_root_path == NULL) {
if (getcwd(path, sizeof(path)) == NULL)
fatal("getcwd: %s", errno_s);
kore_root_path = kore_strdup(path);
kore_log(LOG_NOTICE,
"privsep: no root path set, using working directory");
}
if (getuid() != 0 && skip_chroot == 0) {
fatal("cannot chroot, use -n to skip it");
}
if (skip_runas != 1 && runas_user == NULL) {
if (skip_runas != 1 && kore_runas_user == NULL) {
fatal("missing runas user, use -r to skip it");
}
if (getuid() != 0 && skip_runas == 0) {
fatal("cannot drop privileges, use -r to skip it");
}
if (skip_runas) {
kore_log(LOG_WARNING, "privsep: will not change user");
} else {
#if !defined(KORE_NO_TLS)
if (keymgr_runas_user == NULL) {
kore_log(LOG_NOTICE,
"privsep: no keymgr_runas set, using 'runas` user");
keymgr_runas_user = kore_strdup(kore_runas_user);
}
#endif
}
#if !defined(KORE_NO_TLS)
if (keymgr_root_path == NULL) {
kore_log(LOG_NOTICE,
"privsep: no keymgr_root set, using 'root` directory");
keymgr_root_path = kore_strdup(kore_root_path);
}
#endif
if (skip_chroot)
kore_log(LOG_WARNING, "privsep: will not chroot");
}
void
@ -271,7 +302,7 @@ kore_parse_config_file(FILE *fp)
#endif
if (!strcmp(p, "}") && current_domain != NULL)
domain_tls_init();
current_domain = NULL;
if (!strcmp(p, "}")) {
lineno++;
@ -466,23 +497,23 @@ configure_client_verify_depth(char *value)
}
static int
configure_client_certificates(char *options)
configure_client_verify(char *options)
{
char *argv[3];
if (current_domain == NULL) {
printf("client_certificates not specified in domain context\n");
printf("client_verify not specified in domain context\n");
return (KORE_RESULT_ERROR);
}
kore_split_string(options, " ", argv, 3);
if (argv[0] == NULL) {
printf("client_certificate is missing a parameter\n");
printf("client_verify is missing a parameter\n");
return (KORE_RESULT_ERROR);
}
if (current_domain->cafile != NULL) {
printf("client_certificate already set for %s\n",
printf("client_verify already set for %s\n",
current_domain->domain);
return (KORE_RESULT_ERROR);
}
@ -541,6 +572,26 @@ configure_certkey(char *path)
return (KORE_RESULT_OK);
}
static int
configure_keymgr_runas(char *user)
{
if (keymgr_runas_user != NULL)
kore_free(keymgr_runas_user);
keymgr_runas_user = kore_strdup(user);
return (KORE_RESULT_OK);
}
static int
configure_keymgr_root(char *root)
{
if (keymgr_root_path != NULL)
kore_free(keymgr_root_path);
keymgr_root_path = kore_strdup(root);
return (KORE_RESULT_OK);
}
#endif /* !KORE_NO_TLS */
static int
@ -1090,11 +1141,11 @@ configure_websocket_timeout(char *option)
#endif /* !KORE_NO_HTTP */
static int
configure_chroot(char *path)
configure_root(char *path)
{
if (chroot_path != NULL)
kore_free(chroot_path);
chroot_path = kore_strdup(path);
if (kore_root_path != NULL)
kore_free(kore_root_path);
kore_root_path = kore_strdup(path);
return (KORE_RESULT_OK);
}
@ -1102,9 +1153,9 @@ configure_chroot(char *path)
static int
configure_runas(char *user)
{
if (runas_user != NULL)
kore_free(runas_user);
runas_user = kore_strdup(user);
if (kore_runas_user != NULL)
kore_free(kore_runas_user);
kore_runas_user = kore_strdup(user);
return (KORE_RESULT_OK);
}
@ -1203,13 +1254,6 @@ configure_socket_backlog(char *option)
return (KORE_RESULT_OK);
}
static void
domain_tls_init(void)
{
kore_domain_tlsinit(current_domain);
current_domain = NULL;
}
#if defined(KORE_USE_PGSQL)
static int
configure_pgsql_conn_max(char *option)

View File

@ -223,6 +223,11 @@ kore_connection_handle(struct connection *c)
switch (c->state) {
#if !defined(KORE_NO_TLS)
case CONN_STATE_TLS_SHAKE:
if (primary_dom->ssl_ctx == NULL) {
kore_log(LOG_NOTICE, "TLS setup not yet complete");
return (KORE_RESULT_ERROR);
}
if (c->ssl == NULL) {
c->ssl = SSL_new(primary_dom->ssl_ctx);
if (c->ssl == NULL) {

View File

@ -54,6 +54,7 @@ int tls_version = KORE_TLS_VERSION_1_2;
#if !defined(KORE_NO_TLS)
static int domain_x509_verify(int, X509_STORE_CTX *);
static void domain_load_crl(struct kore_domain *);
static X509 *domain_load_certificate_chain(SSL_CTX *, const char *, size_t);
static void keymgr_init(void);
static void keymgr_await_data(void);
@ -236,11 +237,10 @@ kore_domain_free(struct kore_domain *dom)
kore_free(dom);
}
void
kore_domain_tlsinit(struct kore_domain *dom)
{
#if !defined(KORE_NO_TLS)
BIO *in;
void
kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
{
RSA *rsa;
X509 *x509;
EVP_PKEY *pkey;
@ -251,7 +251,10 @@ kore_domain_tlsinit(struct kore_domain *dom)
EC_KEY *ecdh;
#endif
kore_debug("kore_domain_sslstart(%s)", dom->domain);
kore_debug("kore_domain_tlsinit(%s)", dom->domain);
if (dom->ssl_ctx != NULL)
SSL_CTX_free(dom->ssl_ctx);
#if !defined(LIBRESSL_VERSION_TEXT) && OPENSSL_VERSION_NUMBER >= 0x10100000L
if ((method = TLS_method()) == NULL)
@ -299,20 +302,8 @@ kore_domain_tlsinit(struct kore_domain *dom)
return;
}
#endif
if (!SSL_CTX_use_certificate_chain_file(dom->ssl_ctx, dom->certfile)) {
fatal("SSL_CTX_use_certificate_chain_file(%s): %s",
dom->certfile, ssl_errno_s);
}
if ((in = BIO_new(BIO_s_file())) == NULL)
fatal("BIO_new: %s", ssl_errno_s);
if (BIO_read_filename(in, dom->certfile) <= 0)
fatal("BIO_read_filename: %s", ssl_errno_s);
if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL)
fatal("PEM_read_bio_X509: %s", ssl_errno_s);
BIO_free(in);
x509 = domain_load_certificate_chain(dom->ssl_ctx, pem, pemlen);
if ((pkey = X509_get_pubkey(x509)) == NULL)
fatal("certificate has no public key");
@ -392,10 +383,9 @@ kore_domain_tlsinit(struct kore_domain *dom)
SSL_CTX_set_info_callback(dom->ssl_ctx, kore_tls_info_callback);
SSL_CTX_set_tlsext_servername_callback(dom->ssl_ctx, kore_tls_sni_cb);
kore_free(dom->certfile);
dom->certfile = NULL;
#endif
X509_free(x509);
}
#endif
void
kore_domain_callback(void (*cb)(struct kore_domain *))
@ -756,4 +746,52 @@ domain_x509_verify(int ok, X509_STORE_CTX *ctx)
return (ok);
}
/*
* What follows is basically a reimplementation of
* SSL_CTX_use_certificate_chain_file() from OpenSSL but with our
* BIO set to the pem data that we received.
*/
static X509 *
domain_load_certificate_chain(SSL_CTX *ctx, const char *data, size_t len)
{
BIO *in;
unsigned long err;
X509 *x, *ca;
/* because OpenSSL likes taking ints as buffer sizes. */
if (len > INT_MAX)
fatal("domain_load_certificate_chain: len > INT_MAX");
ERR_clear_error();
if ((in = BIO_new_mem_buf(data, len)) == NULL)
fatal("BIO_new_mem_buf: %s", ssl_errno_s);
if ((x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL)) == NULL)
fatal("PEM_read_bio_X509_AUX: %s", ssl_errno_s);
/* refcount for x509 will go up one. */
if (SSL_CTX_use_certificate(ctx, x) == 0)
fatal("SSL_CTX_use_certificate: %s", ssl_errno_s);
SSL_CTX_clear_chain_certs(ctx);
ERR_clear_error();
while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL) {
/* ca its reference count won't be increased. */
if (SSL_CTX_add0_chain_cert(ctx, ca) == 0)
fatal("SSL_CTX_add0_chain_cert: %s", ssl_errno_s);
}
err = ERR_peek_last_error();
if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
ERR_GET_REASON(err) != PEM_R_NO_START_LINE)
fatal("PEM_read_bio_X509: %s", ssl_errno_s);
BIO_free(in);
return (x);
}
#endif

View File

@ -59,7 +59,7 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
struct stat st;
int len;
struct filemap_entry *entry;
char regex[1024];
char regex[1024], fpath[PATH_MAX];
sz = strlen(root);
if (sz == 0)
@ -68,7 +68,11 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
if (root[0] != '/' || root[sz - 1] != '/')
return (KORE_RESULT_ERROR);
if (stat(path, &st) == -1)
len = snprintf(fpath, sizeof(fpath), "%s/%s", kore_root_path, path);
if (len == -1 || (size_t)len >= sizeof(regex))
fatal("kore_filemap_create: failed to concat paths");
if (stat(fpath, &st) == -1)
return (KORE_RESULT_ERROR);
len = snprintf(regex, sizeof(regex), "^%s.*$", root);

View File

@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/evp.h>
@ -46,24 +46,36 @@ static TAILQ_HEAD(, key) keys;
extern volatile sig_atomic_t sig_recv;
static int initialized = 0;
static void keymgr_reload(void);
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 *);
static void keymgr_entropy_request(struct kore_msg *, const void *);
static void keymgr_certificate_request(struct kore_msg *, const void *);
static void keymgr_submit_certificates(struct kore_domain *, u_int16_t);
static void keymgr_rsa_encrypt(struct kore_msg *, const void *,
struct key *);
static void keymgr_ecdsa_sign(struct kore_msg *, const void *,
struct key *);
char *keymgr_root_path = NULL;
char *keymgr_runas_user = NULL;
void
kore_keymgr_run(void)
{
int quit;
u_int64_t now, last_seed;
quit = 0;
kore_listener_cleanup();
kore_module_cleanup();
kore_worker_privdrop(keymgr_runas_user, keymgr_root_path);
if (rand_file != NULL) {
keymgr_load_randfile();
keymgr_save_randfile();
@ -71,15 +83,7 @@ kore_keymgr_run(void)
kore_log(LOG_WARNING, "no rand_file location specified");
}
quit = 0;
initialized = 1;
TAILQ_INIT(&keys);
kore_listener_cleanup();
kore_module_cleanup();
kore_domain_callback(keymgr_load_privatekey);
kore_worker_privdrop(runas_user, chroot_path);
net_init();
kore_connection_init();
@ -88,8 +92,13 @@ kore_keymgr_run(void)
kore_msg_worker_init();
kore_msg_register(KORE_MSG_KEYMGR_REQ, keymgr_msg_recv);
kore_msg_register(KORE_MSG_ENTROPY_REQ, keymgr_entropy_request);
kore_msg_register(KORE_MSG_CERTIFICATE_REQ, keymgr_certificate_request);
keymgr_reload();
RAND_poll();
last_seed = 0;
kore_log(LOG_NOTICE, "key manager started");
while (quit != 1) {
@ -106,6 +115,9 @@ kore_keymgr_run(void)
case SIGTERM:
quit = 1;
break;
case SIGUSR1:
keymgr_reload();
break;
default:
break;
}
@ -116,18 +128,19 @@ kore_keymgr_run(void)
kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
}
kore_keymgr_cleanup();
kore_keymgr_cleanup(1);
kore_platform_event_cleanup();
kore_connection_cleanup();
net_cleanup();
}
void
kore_keymgr_cleanup(void)
kore_keymgr_cleanup(int final)
{
struct key *key, *next;
kore_log(LOG_NOTICE, "cleaning up keys");
if (final)
kore_log(LOG_NOTICE, "cleaning up keys");
if (initialized == 0)
return;
@ -141,6 +154,69 @@ kore_keymgr_cleanup(void)
}
}
static void
keymgr_reload(void)
{
struct kore_domain *dom;
kore_log(LOG_INFO, "(re)loading certificates and keys");
kore_keymgr_cleanup(0);
TAILQ_INIT(&keys);
kore_domain_callback(keymgr_load_privatekey);
/* can't use kore_domain_callback() due to dst parameter. */
TAILQ_FOREACH(dom, &domains, list)
keymgr_submit_certificates(dom, KORE_MSG_WORKER_ALL);
}
static void
keymgr_submit_certificates(struct kore_domain *dom, u_int16_t dst)
{
int fd;
struct stat st;
ssize_t ret;
size_t len;
struct kore_x509_msg *msg;
u_int8_t *payload;
if ((fd = open(dom->certfile, O_RDONLY)) == -1)
fatal("open(%s): %s", dom->certfile, errno_s);
if (fstat(fd, &st) == -1)
fatal("stat(%s): %s", dom->certfile, errno_s);
if (!S_ISREG(st.st_mode))
fatal("%s is not a file", dom->certfile);
if (st.st_size <= 0 || st.st_size > (1024 * 1024 * 5)) {
fatal("%s length is not valid (%jd)", dom->certfile,
(intmax_t)st.st_size);
}
len = sizeof(*msg) + st.st_size;
payload = kore_calloc(1, len);
msg = (struct kore_x509_msg *)payload;
msg->domain_len = strlen(dom->domain);
if (msg->domain_len > sizeof(msg->domain))
fatal("domain name '%s' too long", dom->domain);
memcpy(msg->domain, dom->domain, msg->domain_len);
msg->data_len = st.st_size;
ret = read(fd, &msg->data[0], msg->data_len);
if (ret == 0)
fatal("eof while reading %s", dom->certfile);
if ((size_t)ret != msg->data_len) {
fatal("bad read on %s: expected %zu, got %zd",
dom->certfile, msg->data_len, ret);
}
kore_msg_send(dst, KORE_MSG_CERTIFICATE, payload, len);
kore_free(payload);
close(fd);
}
static void
keymgr_load_randfile(void)
{
@ -245,25 +321,29 @@ keymgr_load_privatekey(struct kore_domain *dom)
FILE *fp;
struct key *key;
if (dom->certkey == NULL)
return;
if ((fp = fopen(dom->certkey, "r")) == NULL)
fatal("failed to open private key: %s", dom->certkey);
key = kore_malloc(sizeof(*key));
key = kore_calloc(1, sizeof(*key));
key->dom = dom;
if ((key->pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL)
fatal("PEM_read_PrivateKey: %s", ssl_errno_s);
(void)fclose(fp);
kore_free(dom->certkey);
dom->certkey = NULL;
TAILQ_INSERT_TAIL(&keys, key, list);
}
static void
keymgr_certificate_request(struct kore_msg *msg, const void *data)
{
struct kore_domain *dom;
TAILQ_FOREACH(dom, &domains, list)
keymgr_submit_certificates(dom, msg->src);
}
static void
keymgr_entropy_request(struct kore_msg *msg, const void *data)
{
@ -290,8 +370,11 @@ keymgr_msg_recv(struct kore_msg *msg, const void *data)
return;
req = (const struct kore_keyreq *)data;
if (msg->length != (sizeof(*req) + req->data_len))
return;
if (req->domain_len > KORE_DOMAINNAME_LEN)
return;
key = NULL;
TAILQ_FOREACH(key, &keys, list) {

View File

@ -41,11 +41,11 @@ pid_t kore_pid = -1;
u_int16_t cpu_count = 1;
int foreground = 0;
int kore_debug = 0;
u_int8_t worker_count = 0;
int skip_chroot = 0;
char *chroot_path = NULL;
int skip_runas = 0;
char *runas_user = NULL;
int skip_chroot = 0;
u_int8_t worker_count = 0;
char *kore_root_path = NULL;
char *kore_runas_user = NULL;
u_int32_t kore_socket_backlog = 5000;
char *kore_pidfile = KORE_PIDFILE_DEFAULT;
char *kore_tls_cipher_list = KORE_DEFAULT_CIPHER_LIST;
@ -394,6 +394,8 @@ kore_signal_setup(void)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGTERM, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGUSR1, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (foreground) {
if (sigaction(SIGINT, &sa, NULL) == -1)
@ -486,6 +488,7 @@ kore_server_start(void)
quit = 0;
worker_max_connections = tmp;
while (quit != 1) {
if (sig_recv != 0) {
switch (sig_recv) {
@ -499,6 +502,9 @@ kore_server_start(void)
quit = 1;
kore_worker_dispatch_signal(sig_recv);
continue;
case SIGUSR1:
kore_worker_dispatch_signal(sig_recv);
break;
default:
break;
}

View File

@ -129,7 +129,7 @@ kore_msg_register(u_int8_t id, void (*cb)(struct kore_msg *, const void *))
}
void
kore_msg_send(u_int16_t dst, u_int8_t id, const void *data, u_int32_t len)
kore_msg_send(u_int16_t dst, u_int8_t id, const void *data, size_t len)
{
struct kore_msg m;

View File

@ -620,7 +620,7 @@ fatal(const char *fmt, ...)
#if !defined(KORE_NO_TLS)
if (worker != NULL && worker->id == KORE_WORKER_KEYMGR)
kore_keymgr_cleanup();
kore_keymgr_cleanup(1);
#endif
printf("%s: %s\n", __progname, buf);

View File

@ -76,7 +76,8 @@ static inline int kore_worker_acceptlock_obtain(u_int64_t);
static inline int kore_worker_acceptlock_release(u_int64_t);
#if !defined(KORE_NO_TLS)
static void worker_entropy_recv(struct kore_msg *, const void *);
static void worker_entropy_recv(struct kore_msg *, const void *);
static void worker_certificate_recv(struct kore_msg *, const void *);
#endif
static struct kore_worker *kore_workers;
@ -225,8 +226,13 @@ kore_worker_privdrop(const char *runas, const char *root)
struct rlimit rl;
struct passwd *pw = NULL;
if (root == NULL)
fatal("no root directory for kore_worker_privdrop");
/* Must happen before chroot. */
if (skip_runas == 0) {
if (runas == NULL)
fatal("no runas user given and -r not specified");
pw = getpwnam(runas);
if (pw == NULL) {
fatal("cannot getpwnam(\"%s\") for user: %s",
@ -242,6 +248,9 @@ kore_worker_privdrop(const char *runas, const char *root)
if (chdir("/") == -1)
fatal("cannot chdir(\"/\"): %s", errno_s);
} else {
if (chdir(root) == -1)
fatal("cannot chdir(\"/\"): %s", errno_s);
}
if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
@ -309,7 +318,7 @@ kore_worker_entry(struct kore_worker *kw)
}
#endif
kore_worker_privdrop(runas_user, chroot_path);
kore_worker_privdrop(kore_runas_user, kore_root_path);
net_init();
#if !defined(KORE_NO_HTTP)
@ -343,6 +352,11 @@ kore_worker_entry(struct kore_worker *kw)
#if !defined(KORE_NO_TLS)
last_seed = 0;
kore_msg_register(KORE_MSG_ENTROPY_RESP, worker_entropy_recv);
kore_msg_register(KORE_MSG_CERTIFICATE, worker_certificate_recv);
if (worker->restarted) {
kore_msg_send(KORE_WORKER_KEYMGR,
KORE_MSG_CERTIFICATE_REQ, NULL, 0);
}
#endif
if (nlisteners == 0)
@ -357,6 +371,7 @@ kore_worker_entry(struct kore_worker *kw)
}
kore_module_onload();
worker->restarted = 0;
for (;;) {
if (sig_recv != 0) {
@ -530,6 +545,7 @@ kore_worker_wait(int final)
}
kore_log(LOG_NOTICE, "restarting worker %d", kw->id);
kw->restarted = 1;
kore_msg_parent_remove(kw);
kore_worker_spawn(kw->id, kw->cpu);
kore_msg_parent_add(kw);
@ -631,11 +647,53 @@ worker_entropy_recv(struct kore_msg *msg, const void *data)
{
if (msg->length != 1024) {
kore_log(LOG_WARNING,
"invalid entropy response (got:%u - wanted:1024)",
"invalid entropy response (got:%zu - wanted:1024)",
msg->length);
}
RAND_poll();
RAND_seed(data, msg->length);
}
static void
worker_certificate_recv(struct kore_msg *msg, const void *data)
{
struct kore_domain *dom;
const struct kore_x509_msg *req;
if (msg->length < sizeof(*req)) {
kore_log(LOG_WARNING,
"short KORE_MSG_CERTIFICATE message (%zu)", msg->length);
return;
}
req = (const struct kore_x509_msg *)data;
if (msg->length != (sizeof(*req) + req->data_len)) {
kore_log(LOG_WARNING,
"invalid KORE_MSG_CERTIFICATE payload (%zu)", msg->length);
return;
}
if (req->domain_len > KORE_DOMAINNAME_LEN) {
kore_log(LOG_WARNING,
"invalid KORE_MSG_CERTIFICATE domain (%u)",
req->domain_len);
return;
}
dom = NULL;
TAILQ_FOREACH(dom, &domains, list) {
if (!strncmp(dom->domain, req->domain, req->domain_len))
break;
}
if (dom == NULL) {
kore_log(LOG_WARNING,
"got KORE_MSG_CERTIFICATE for domain that does not exist");
return;
}
/* reinitialize the domain TLS context. */
kore_domain_tlsinit(dom, req->data, req->data_len);
}
#endif