Add acmev2 (RFC8555) support to Kore.

A new acme process is created that communicates with the acme servers.

This process does not hold any of your private keys (no account keys,
no domain keys etc).

Whenever the acme process requires a signed payload it will ask the keymgr
process to do the signing with the relevant keys.

This process is also sandboxed with pledge+unveil on OpenBSD and seccomp
syscall filtering on Linux.

The implementation only supports the tls-alpn-01 challenge. This means that
you do not need to open additional ports on your machine.

http-01 and dns-01 are currently not supported (no wildcard support).

A new configuration option "acme_provider" is available and can be set
to the acme server its directory. By default this will point to the
live letsencrypt environment:
    https://acme-v02.api.letsencrypt.org/directory

The acme process can be controlled via the following config options:
  - acme_root (where the acme process will chroot/chdir into).
  - acme_runas (the user the acme process will run as).

  If none are set, the values from 'root' and 'runas' are taken.

If you want to turn on acme for domains you do it as follows:

domain kore.io {
	acme yes
}

You do not need to specify certkey/certfile anymore, if they are present
still
they will be overwritten by the acme system.

The keymgr will store all certificates and keys under its root
(keymgr_root), the account key is stored as "/account-key.pem" and all
obtained certificates go under "certificates/<domain>/fullchain.pem" while
keys go under "certificates/<domain>/key.pem".

Kore will automatically renew certificates if they will expire in 7 days
or less.
This commit is contained in:
Joris Vink 2019-11-06 19:33:53 +01:00
parent eef1a05868
commit c78535aa5d
19 changed files with 3358 additions and 412 deletions

View File

@ -102,6 +102,13 @@ ifeq ("$(OSNAME)", "freebsd")
KORE_CURL_INC=-I/usr/local/include
endif
ifneq ("$(ACME)", "")
S_SRC+=src/acme.c
CURL=1
CFLAGS+=-DKORE_USE_ACME
FEATURES+=-DKORE_USE_ACME
endif
ifneq ("$(CURL)", "")
S_SRC+=src/curl.c
KORE_CURL_LIB?=$(shell curl-config --libs)

View File

@ -23,8 +23,8 @@
* your workers with custom callbacks defined per message ID.
*/
/* Your code shouldn't use IDs < 100. */
#define MY_MESSAGE_ID 100
/* Your code shouldn't use IDs <= KORE_MSG_APP_BASE. */
#define MY_MESSAGE_ID KORE_MSG_APP_BASE + 1
int init(int);
int page(struct http_request *);

60
include/kore/acme.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2019 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __H_ACME_H
#define __H_ACME_H
#if defined(__cplusplus)
extern "C" {
#endif
/*
* All acme paths are relative to the keymgr_root directory.
*/
#define KORE_ACME_ACCOUNT_KEY "account-key.pem"
#define KORE_ACME_CERTDIR "certificates"
#define KORE_ACME_RSAKEY_E (KORE_MSG_ACME_BASE + 1)
#define KORE_ACME_RSAKEY_N (KORE_MSG_ACME_BASE + 2)
#define KORE_ACME_SIGN (KORE_MSG_ACME_BASE + 3)
#define KORE_ACME_SIGN_RESULT (KORE_MSG_ACME_BASE + 4)
#define KORE_ACME_PROC_READY (KORE_MSG_ACME_BASE + 5)
#define KORE_ACME_ACCOUNT_CREATE (KORE_MSG_ACME_BASE + 10)
#define KORE_ACME_ACCOUNT_RESOLVE (KORE_MSG_ACME_BASE + 11)
#define KORE_ACME_ORDER_CREATE (KORE_MSG_ACME_BASE + 12)
#define KORE_ACME_CSR_REQUEST (KORE_MSG_ACME_BASE + 13)
#define KORE_ACME_CSR_RESPONSE (KORE_MSG_ACME_BASE + 14)
#define KORE_ACME_INSTALL_CERT (KORE_MSG_ACME_BASE + 15)
#define KORE_ACME_ORDER_FAILED (KORE_MSG_ACME_BASE + 16)
#define KORE_ACME_CHALLENGE_CERT (KORE_MSG_ACME_BASE + 20)
#define KORE_ACME_CHALLENGE_SET_CERT (KORE_MSG_ACME_BASE + 21)
#define KORE_ACME_CHALLENGE_CLEAR_CERT (KORE_MSG_ACME_BASE + 22)
void kore_acme_init(void);
void kore_acme_run(void);
void kore_acme_setup(void);
int kore_acme_tls_alpn(SSL *, const unsigned char **, unsigned char *,
const unsigned char *, unsigned int, void *);
extern char *acme_provider;
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -78,6 +78,8 @@ extern int daemon(int, int);
#define KORE_USE_PLATFORM_PLEDGE 1
#endif
#define KORE_RSAKEY_BITS 4096
#define KORE_RESULT_ERROR 0
#define KORE_RESULT_OK 1
#define KORE_RESULT_RETRY 2
@ -86,6 +88,8 @@ extern int daemon(int, int);
#define KORE_TLS_VERSION_1_2 1
#define KORE_TLS_VERSION_BOTH 2
#define KORE_BASE64_RAW 0x0001
#define KORE_WAIT_INFINITE (u_int64_t)-1
#define KORE_RESEED_TIME (1800 * 1000)
@ -128,6 +132,9 @@ extern int daemon(int, int);
#define X509_CN_LENGTH (ub_common_name + 1)
#define KORE_PEM_CERT_CHAIN 1
#define KORE_DER_CERT_DATA 2
/* XXX hackish. */
#if !defined(KORE_NO_HTTP)
struct http_request;
@ -195,6 +202,7 @@ TAILQ_HEAD(netbuf_head, netbuf);
#define CONN_CLOSE_EMPTY 0x02
#define CONN_WS_CLOSE_SENT 0x04
#define CONN_IS_BUSY 0x08
#define CONN_ACME_CHALLENGE 0x10
#define KORE_IDLE_TIMER_MAX 5000
@ -303,6 +311,12 @@ struct kore_domain {
struct kore_buf *logbuf;
struct kore_server *server;
#if defined(KORE_USE_ACME)
int acme;
int acme_challenge;
void *acme_cert;
size_t acme_cert_len;
#endif
char *cafile;
char *crlfile;
char *certfile;
@ -431,11 +445,9 @@ struct kore_alog_header {
u_int16_t loglen;
} __attribute__((packed));
#define KORE_WORKER_MAX UCHAR_MAX
struct kore_worker {
u_int8_t id;
u_int8_t cpu;
u_int16_t id;
u_int16_t cpu;
#if defined(__linux__)
int tracing;
#endif
@ -600,7 +612,17 @@ struct kore_timer {
TAILQ_ENTRY(kore_timer) list;
};
#define KORE_WORKER_KEYMGR 0
/*
* Keymgr process is worker index 0, but id 2000.
* Acme process is worker index 1, but id 2001.
*/
#define KORE_WORKER_KEYMGR_IDX 0
#define KORE_WORKER_ACME_IDX 1
#define KORE_WORKER_BASE 2
#define KORE_WORKER_KEYMGR 2000
#define KORE_WORKER_ACME 2001
#define KORE_WORKER_MAX UCHAR_MAX
#define KORE_WORKER_POLICY_RESTART 1
#define KORE_WORKER_POLICY_TERMINATE 2
@ -616,6 +638,10 @@ struct kore_timer {
#define KORE_MSG_CRL 9
#define KORE_MSG_ACCEPT_AVAILABLE 10
#define KORE_PYTHON_SEND_OBJ 11
#define KORE_MSG_ACME_BASE 100
/* messages for applications should start at 201. */
#define KORE_MSG_APP_BASE 200
/* Predefined message targets. */
#define KORE_MSG_PARENT 1000
@ -630,15 +656,13 @@ struct kore_msg {
struct kore_keyreq {
int padding;
char domain[KORE_DOMAINNAME_LEN];
u_int16_t domain_len;
u_int16_t data_len;
char domain[KORE_DOMAINNAME_LEN + 1];
size_t data_len;
u_int8_t data[];
};
struct kore_x509_msg {
char domain[KORE_DOMAINNAME_LEN];
u_int16_t domain_len;
char domain[KORE_DOMAINNAME_LEN + 1];
size_t data_len;
u_int8_t data[];
};
@ -666,6 +690,8 @@ extern char *rand_file;
extern int keymgr_active;
extern char *keymgr_runas_user;
extern char *keymgr_root_path;
extern char *acme_runas_user;
extern char *acme_root_path;
extern u_int8_t nlisteners;
extern u_int16_t cpu_count;
@ -696,9 +722,11 @@ void kore_worker_init(void);
void kore_worker_make_busy(void);
void kore_worker_shutdown(void);
void kore_worker_dispatch_signal(int);
void kore_worker_spawn(u_int16_t, u_int16_t);
void kore_worker_entry(struct kore_worker *);
void kore_worker_privdrop(const char *, const char *);
void kore_worker_spawn(u_int16_t, u_int16_t, u_int16_t);
int kore_worker_keymgr_response_verify(struct kore_msg *,
const void *, struct kore_domain **);
struct kore_worker *kore_worker_data(u_int8_t);
@ -706,13 +734,13 @@ void kore_platform_init(void);
void kore_platform_sandbox(void);
void kore_platform_event_init(void);
void kore_platform_event_cleanup(void);
void kore_platform_proctitle(char *);
void kore_platform_disable_read(int);
void kore_platform_disable_write(int);
void kore_platform_enable_accept(void);
void kore_platform_disable_accept(void);
void kore_platform_event_wait(u_int64_t);
void kore_platform_event_all(int, void *);
void kore_platform_proctitle(const char *);
void kore_platform_schedule_read(int, void *);
void kore_platform_schedule_write(int, void *);
void kore_platform_event_schedule(int, int, int, void *);
@ -830,10 +858,15 @@ long long kore_strtonum(const char *, int, long long, long long, int *);
double kore_strtodouble(const char *, long double, long double, int *);
int kore_base64_encode(const void *, size_t, char **);
int kore_base64_decode(const char *, u_int8_t **, size_t *);
int kore_base64url_encode(const void *, size_t, char **, int);
int kore_base64url_decode(const char *, u_int8_t **, size_t *, int);
void *kore_mem_find(void *, size_t, const void *, size_t);
char *kore_text_trim(char *, size_t);
char *kore_read_line(FILE *, char *, size_t);
EVP_PKEY *kore_rsakey_load(const char *);
EVP_PKEY *kore_rsakey_generate(const char *);
#if !defined(KORE_NO_HTTP)
void kore_websocket_handshake(struct http_request *,
const char *, const char *, const char *);
@ -885,7 +918,8 @@ void kore_domain_load_crl(void);
void kore_domain_keymgr_init(void);
void kore_domain_callback(void (*cb)(struct kore_domain *));
int kore_domain_attach(struct kore_domain *, struct kore_server *);
void kore_domain_tlsinit(struct kore_domain *, const void *, size_t);
void kore_domain_tlsinit(struct kore_domain *, int,
const void *, size_t);
void kore_domain_crl_add(struct kore_domain *, const void *, size_t);
#if !defined(KORE_NO_HTTP)
int kore_module_handler_new(struct kore_domain *, const char *,
@ -930,6 +964,8 @@ struct kore_validator *kore_validator_lookup(const char *);
void fatal(const char *, ...) __attribute__((noreturn));
void fatalx(const char *, ...) __attribute__((noreturn));
const char *kore_worker_name(int);
void kore_debug_internal(char *, int, const char *, ...);
u_int16_t net_read16(u_int8_t *);

View File

@ -164,8 +164,8 @@ void kore_seccomp_init(void);
void kore_seccomp_drop(void);
void kore_seccomp_enable(void);
void kore_seccomp_traceme(void);
int kore_seccomp_trace(pid_t, int);
int kore_seccomp_syscall_resolve(const char *);
int kore_seccomp_trace(struct kore_worker *, int);
int kore_seccomp_filter(const char *, void *, size_t);
const char *kore_seccomp_syscall_name(long);

View File

@ -208,7 +208,7 @@ kore_accesslog_gather(void *arg, u_int64_t now, int force)
if (logbuf == NULL)
logbuf = kore_buf_alloc(LOGBUF_SIZE);
for (id = 0; id < worker_count; id++) {
for (id = KORE_WORKER_BASE; id < worker_count; id++) {
kw = kore_worker_data(id);
accesslog_lock(kw);

1684
src/acme.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -236,7 +236,7 @@ kore_platform_disable_write(int fd)
}
void
kore_platform_proctitle(char *title)
kore_platform_proctitle(const char *title)
{
#ifdef __MACH__
kore_proctitle(title);
@ -299,6 +299,9 @@ kore_platform_sandbox(void)
void
kore_platform_pledge(void)
{
if (worker->id == KORE_WORKER_KEYMGR || worker->id == KORE_WORKER_ACME)
return;
if (pledge(pledges, NULL) == -1)
fatal("failed to pledge process");
}

View File

@ -45,13 +45,18 @@
#include "curl.h"
#endif
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
#if defined(__linux__)
#include "seccomp.h"
#endif
/* XXX - This is becoming a clusterfuck. Fix it. */
static int configure_load(char *);
static int configure_load(char *);
static void configure_check_var(char **, const char *, const char *);
#if defined(KORE_SINGLE_BINARY)
static FILE *config_file_write(void);
@ -61,6 +66,13 @@ extern u_int32_t asset_len_builtin_kore_conf;
static int configure_file(char *);
#endif
#if defined(KORE_USE_ACME)
static int configure_acme(char *);
static int configure_acme_root(char *);
static int configure_acme_runas(char *);
static int configure_acme_provider(char *);
#endif
static int configure_tls(char *);
static int configure_server(char *);
static int configure_include(char *);
@ -155,15 +167,18 @@ static struct {
int (*configure)(char *);
} config_directives[] = {
{ "tls", configure_tls },
{ "server", configure_server },
{ "include", configure_include },
#if defined(KORE_USE_ACME)
{ "acme", configure_acme },
#endif
{ "bind", configure_bind },
{ "unix", configure_bind_unix },
{ "load", configure_load },
{ "domain", configure_domain },
{ "server", configure_server },
{ "attach", configure_attach },
{ "certfile", configure_certfile },
{ "certkey", configure_certkey },
{ "certfile", configure_certfile },
{ "include", configure_include },
{ "unix", configure_bind_unix },
{ "client_verify", configure_client_verify },
{ "client_verify_depth", configure_client_verify_depth },
#if defined(KORE_USE_PYTHON)
@ -209,6 +224,11 @@ static struct {
{ "rand_file", configure_rand_file },
{ "keymgr_runas", configure_keymgr_runas },
{ "keymgr_root", configure_keymgr_root },
#if defined(KORE_USE_ACME)
{ "acme_runas", configure_acme_runas },
{ "acme_root", configure_acme_root },
{ "acme_provider", configure_acme_provider },
#endif
#if defined(KORE_USE_PLATFORM_PLEDGE)
{ "pledge", configure_add_pledge },
#endif
@ -326,22 +346,21 @@ kore_parse_config(void)
if (!kore_quiet)
kore_log(LOG_WARNING, "privsep: will not change user");
} else {
if (keymgr_runas_user == NULL) {
if (!kore_quiet) {
kore_log(LOG_NOTICE, "privsep: no keymgr_runas "
"set, using 'runas` user");
}
keymgr_runas_user = kore_strdup(kore_runas_user);
}
configure_check_var(&keymgr_runas_user, kore_runas_user,
"privsep: no keymgr_runas set, using 'runas` user");
#if defined(KORE_USE_ACME)
configure_check_var(&acme_runas_user, kore_runas_user,
"privsep: no acme_runas set, using 'runas` user");
#endif
}
if (keymgr_root_path == NULL) {
if (!kore_quiet) {
kore_log(LOG_NOTICE, "privsep: no keymgr_root set, "
"using 'root` directory");
}
keymgr_root_path = kore_strdup(kore_root_path);
}
configure_check_var(&keymgr_root_path, kore_root_path,
"privsep: no keymgr_root set, using 'root` directory");
#if defined(KORE_USE_ACME)
configure_check_var(&acme_root_path, kore_root_path,
"privsep: no acme_root set, using 'root` directory");
#endif
if (skip_chroot && !kore_quiet)
kore_log(LOG_WARNING, "privsep: will not chroot");
@ -396,11 +415,19 @@ kore_parse_config_file(FILE *fp)
current_domain->domain);
}
if (current_domain->server->tls == 1 &&
(current_domain->certfile == NULL ||
current_domain->certkey == NULL)) {
fatal("incomplete TLS setup for '%s'",
current_domain->domain);
if (current_domain->server->tls == 1) {
#if defined(KORE_USE_ACME)
if (current_domain->acme) {
lineno++;
current_domain = NULL;
continue;
}
#endif
if (current_domain->certfile == NULL ||
current_domain->certkey == NULL) {
fatal("incomplete TLS setup for '%s'",
current_domain->domain);
}
}
current_domain = NULL;
@ -478,6 +505,16 @@ kore_configure_setting(const char *name, char *value)
}
#endif
static void
configure_check_var(char **var, const char *other, const char *logmsg)
{
if (*var == NULL) {
if (!kore_quiet)
kore_log(LOG_NOTICE, "%s", logmsg);
*var = kore_strdup(other);
}
}
static int
configure_include(char *path)
{
@ -545,6 +582,82 @@ configure_tls(char *yesno)
return (KORE_RESULT_OK);
}
#if defined(KORE_USE_ACME)
static int
configure_acme(char *yesno)
{
int len;
char path[MAXPATHLEN];
if (current_domain == NULL) {
printf("acme directive not inside a domain context\n");
return (KORE_RESULT_ERROR);
}
if (strchr(current_domain->domain, '*')) {
printf("wildcards not supported due to lack of dns-01\n");
return (KORE_RESULT_ERROR);
}
if (!strcmp(yesno, "no")) {
current_domain->acme = 0;
} else if (!strcmp(yesno, "yes")) {
current_domain->acme = 1;
/* Override keyfile and certfile locations. */
kore_free(current_domain->certkey);
kore_free(current_domain->certfile);
len = snprintf(path, sizeof(path), "%s/%s/fullchain.pem",
KORE_ACME_CERTDIR, current_domain->domain);
if (len == -1 || (size_t)len >= sizeof(path))
fatal("failed to create certfile path");
current_domain->certfile = kore_strdup(path);
len = snprintf(path, sizeof(path), "%s/%s/key.pem",
KORE_ACME_CERTDIR, current_domain->domain);
if (len == -1 || (size_t)len >= sizeof(path))
fatal("failed to create certkey path");
current_domain->certkey = kore_strdup(path);
} else {
printf("invalid '%s' for yes|no acme option\n", yesno);
return (KORE_RESULT_ERROR);
}
return (KORE_RESULT_OK);
}
static int
configure_acme_runas(char *user)
{
kore_free(acme_runas_user);
acme_runas_user = kore_strdup(user);
return (KORE_RESULT_OK);
}
static int
configure_acme_root(char *root)
{
kore_free(acme_root_path);
acme_root_path = kore_strdup(root);
return (KORE_RESULT_OK);
}
static int
configure_acme_provider(char *provider)
{
kore_free(acme_provider);
acme_provider = kore_strdup(provider);
return (KORE_RESULT_OK);
}
#endif
static int
configure_bind(char *options)
{
@ -767,12 +880,7 @@ configure_certfile(char *path)
return (KORE_RESULT_ERROR);
}
if (current_domain->certfile != NULL) {
printf("certfile specified twice for %s\n",
current_domain->domain);
return (KORE_RESULT_ERROR);
}
kore_free(current_domain->certfile);
current_domain->certfile = kore_strdup(path);
return (KORE_RESULT_OK);
}
@ -785,12 +893,7 @@ configure_certkey(char *path)
return (KORE_RESULT_ERROR);
}
if (current_domain->certkey != NULL) {
printf("certkey specified twice for %s\n",
current_domain->domain);
return (KORE_RESULT_ERROR);
}
kore_free(current_domain->certkey);
current_domain->certkey = kore_strdup(path);
return (KORE_RESULT_OK);
}

View File

@ -274,8 +274,12 @@ kore_connection_handle(struct connection *c)
SSL_set_fd(c->ssl, c->fd);
SSL_set_accept_state(c->ssl);
SSL_set_app_data(c->ssl, c);
SSL_set_ex_data(c->ssl, 0, c);
if (!SSL_set_ex_data(c->ssl, 0, c)) {
kore_debug("SSL_set_ex_data(): %s",
ssl_errno_s);
return (KORE_RESULT_ERROR);
}
}
ERR_clear_error();
@ -293,6 +297,14 @@ kore_connection_handle(struct connection *c)
}
}
#if defined(KORE_USE_ACME)
if (c->flags & CONN_ACME_CHALLENGE) {
kore_log(LOG_INFO, "disconnecting acme client");
kore_connection_disconnect(c);
return (KORE_RESULT_OK);
}
#endif
if (SSL_get_verify_mode(c->ssl) & SSL_VERIFY_PEER) {
c->cert = SSL_get_peer_certificate(c->ssl);
if (c->cert == NULL) {

View File

@ -42,10 +42,13 @@ static struct sock_filter filter_curl[] = {
KORE_SYSCALL_ALLOW(set_robust_list),
/* Other */
KORE_SYSCALL_ALLOW(uname),
KORE_SYSCALL_ALLOW(ioctl),
KORE_SYSCALL_ALLOW(madvise),
KORE_SYSCALL_ALLOW(recvmsg),
KORE_SYSCALL_ALLOW(sendmmsg),
KORE_SYSCALL_ALLOW(faccessat),
KORE_SYSCALL_ALLOW(newfstatat),
KORE_SYSCALL_ALLOW(getpeername),
};
#endif

View File

@ -38,6 +38,10 @@
#include "http.h"
#endif
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
#define KORE_DOMAIN_CACHE 16
#define SSL_SESSION_ID "kore_ssl_sessionid"
@ -256,8 +260,10 @@ kore_domain_free(struct kore_domain *dom)
}
void
kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
kore_domain_tlsinit(struct kore_domain *dom, int type,
const void *data, size_t datalen)
{
const u_int8_t *ptr;
RSA *rsa;
X509 *x509;
EVP_PKEY *pkey;
@ -329,7 +335,30 @@ kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
}
#endif
x509 = domain_load_certificate_chain(dom->ssl_ctx, pem, pemlen);
switch (type) {
case KORE_PEM_CERT_CHAIN:
x509 = domain_load_certificate_chain(dom->ssl_ctx,
data, datalen);
break;
case KORE_DER_CERT_DATA:
ptr = data;
if ((x509 = d2i_X509(NULL, &ptr, datalen)) == NULL)
fatalx("d2i_X509: %s", ssl_errno_s);
if (SSL_CTX_use_certificate(dom->ssl_ctx, x509) == 0)
fatalx("SSL_CTX_use_certificate: %s", ssl_errno_s);
break;
default:
fatalx("%s: unknown type %d", __func__, type);
}
if (x509 == NULL) {
kore_log(LOG_NOTICE, "failed to load certificate for '%s': %s",
dom->domain, ssl_errno_s);
SSL_CTX_free(dom->ssl_ctx);
dom->ssl_ctx = NULL;
return;
}
if ((pkey = X509_get_pubkey(x509)) == NULL)
fatalx("certificate has no public key");
@ -362,8 +391,10 @@ kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
if (!SSL_CTX_use_PrivateKey(dom->ssl_ctx, pkey))
fatalx("SSL_CTX_use_PrivateKey(): %s", ssl_errno_s);
if (!SSL_CTX_check_private_key(dom->ssl_ctx))
fatalx("Public/Private key for %s do not match", dom->domain);
if (!SSL_CTX_check_private_key(dom->ssl_ctx)) {
fatalx("Public/Private key for %s do not match (%s)",
dom->domain, ssl_errno_s);
}
if (tls_dhparam == NULL)
fatalx("No DH parameters given");
@ -415,6 +446,10 @@ kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
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);
#if defined(KORE_USE_ACME)
SSL_CTX_set_alpn_select_cb(dom->ssl_ctx, kore_acme_tls_alpn, dom);
#endif
X509_free(x509);
}
@ -599,18 +634,18 @@ keymgr_rsa_privenc(int flen, const unsigned char *from, unsigned char *to,
if ((dom = RSA_get_app_data(rsa)) == NULL)
fatal("RSA key has no domain attached");
if (strlen(dom->domain) >= KORE_DOMAINNAME_LEN - 1)
fatal("domain name too long");
memset(keymgr_buf, 0, sizeof(keymgr_buf));
req = (struct kore_keyreq *)keymgr_buf;
if (kore_strlcpy(req->domain, dom->domain, sizeof(req->domain)) >=
sizeof(req->domain))
fatal("%s: domain truncated", __func__);
req->data_len = flen;
req->padding = padding;
req->domain_len = strlen(dom->domain);
memcpy(&req->data[0], from, req->data_len);
memcpy(req->domain, dom->domain, req->domain_len);
kore_msg_send(KORE_WORKER_KEYMGR, KORE_MSG_KEYMGR_REQ, keymgr_buf, len);
keymgr_await_data();
@ -663,13 +698,14 @@ keymgr_ecdsa_sign(const unsigned char *dgst, int dgst_len,
#endif
memset(keymgr_buf, 0, sizeof(keymgr_buf));
req = (struct kore_keyreq *)keymgr_buf;
req->data_len = dgst_len;
req->domain_len = strlen(dom->domain);
if (kore_strlcpy(req->domain, dom->domain, sizeof(req->domain)) >=
sizeof(req->domain))
fatal("%s: domain truncated", __func__);
req->data_len = dgst_len;
memcpy(&req->data[0], dgst, req->data_len);
memcpy(req->domain, dom->domain, req->domain_len);
kore_msg_send(KORE_WORKER_KEYMGR, KORE_MSG_KEYMGR_REQ, keymgr_buf, len);
keymgr_await_data();
@ -835,11 +871,11 @@ domain_load_certificate_chain(SSL_CTX *ctx, const void *data, size_t len)
in = BIO_new_mem_buf(data, len);
if ((x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL)) == NULL)
fatal("PEM_read_bio_X509_AUX: %s", ssl_errno_s);
return (NULL);
/* refcount for x509 will go up one. */
if (SSL_CTX_use_certificate(ctx, x) == 0)
fatal("SSL_CTX_use_certificate: %s", ssl_errno_s);
return (NULL);
#if defined(KORE_OPENSSL_NEWER_API)
SSL_CTX_clear_chain_certs(ctx);
@ -853,10 +889,10 @@ domain_load_certificate_chain(SSL_CTX *ctx, const void *data, size_t len)
/* ca its reference count won't be increased. */
#if defined(KORE_OPENSSL_NEWER_API)
if (SSL_CTX_add0_chain_cert(ctx, ca) == 0)
fatal("SSL_CTX_add0_chain_cert: %s", ssl_errno_s);
return (NULL);
#else
if (SSL_CTX_add_extra_chain_cert(ctx, ca) == 0)
fatal("SSL_CTX_add_extra_chain_cert: %s", ssl_errno_s);
return (NULL);
#endif
}
@ -864,7 +900,7 @@ domain_load_certificate_chain(SSL_CTX *ctx, const void *data, size_t len)
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);
return (NULL);
BIO_free(in);

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,10 @@
#include "python_api.h"
#endif
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
volatile sig_atomic_t sig_recv;
struct kore_server_list kore_servers;
u_int8_t nlisteners;
@ -255,6 +259,9 @@ main(int argc, char *argv[])
kore_auth_init();
kore_validator_init();
kore_filemap_init();
#endif
#if defined(KORE_USE_ACME)
kore_acme_init();
#endif
kore_domain_init();
kore_module_init();

View File

@ -220,7 +220,7 @@ kore_platform_disable_accept(void)
}
void
kore_platform_proctitle(char *title)
kore_platform_proctitle(const char *title)
{
kore_proctitle(title);
}

View File

@ -40,30 +40,29 @@ static void msg_type_websocket(struct kore_msg *, const void *);
#endif
static TAILQ_HEAD(, msg_type) msg_types;
static int cacheidx = 0;
static struct connection *conncache[KORE_WORKER_MAX];
static size_t cacheidx = 0;
static struct connection **conncache = NULL;
void
kore_msg_init(void)
{
int i;
for (i = 0; i < KORE_WORKER_MAX; i++)
conncache[i] = NULL;
TAILQ_INIT(&msg_types);
}
void
kore_msg_parent_init(void)
{
u_int8_t i;
u_int8_t idx;
struct kore_worker *kw;
for (i = 0; i < worker_count; i++) {
if (keymgr_active == 0 && i == KORE_WORKER_KEYMGR)
continue;
kw = kore_worker_data(i);
for (idx = 0; idx < worker_count; idx++) {
if (keymgr_active == 0) {
if (idx == KORE_WORKER_KEYMGR_IDX ||
idx == KORE_WORKER_ACME_IDX)
continue;
}
kw = kore_worker_data(idx);
kore_msg_parent_add(kw);
}
@ -83,8 +82,8 @@ kore_msg_parent_add(struct kore_worker *kw)
kw->msg[0]->disconnect = msg_disconnected_worker;
kw->msg[0]->handle = kore_connection_handle;
if (cacheidx >= KORE_WORKER_MAX)
fatal("%s: too many workers", __func__);
conncache = kore_realloc(conncache,
(cacheidx + 1) * sizeof(struct connection *));
conncache[cacheidx++] = kw->msg[0];
@ -187,11 +186,11 @@ msg_recv_packet(struct netbuf *nb)
static int
msg_recv_data(struct netbuf *nb)
{
size_t i;
struct connection *c;
u_int8_t dst;
struct msg_type *type;
int deliver, i;
u_int16_t destination;
int deliver;
u_int16_t dst, destination;
struct kore_msg *msg = (struct kore_msg *)nb->buf;
if ((type = msg_type_lookup(msg->id)) != NULL) {
@ -209,13 +208,20 @@ msg_recv_data(struct netbuf *nb)
if (worker == NULL && type == NULL) {
destination = msg->dst;
for (i = 0; conncache[i] != NULL; i++) {
for (i = 0; i < cacheidx; i++) {
c = conncache[i];
if (c->proto != CONN_PROTO_MSG || c->hdlr_extra == NULL)
if (c->proto != CONN_PROTO_MSG)
fatal("connection not a msg connection");
/*
* If hdlr_extra is NULL it just means the worker
* never started, ignore it.
*/
if (c->hdlr_extra == NULL)
continue;
deliver = 1;
dst = *(u_int8_t *)c->hdlr_extra;
dst = *(u_int16_t *)c->hdlr_extra;
if (destination == KORE_MSG_WORKER_ALL) {
if (keymgr_active && dst == 0)
@ -229,7 +235,7 @@ msg_recv_data(struct netbuf *nb)
continue;
/* This allows the worker to receive the correct id. */
msg->dst = *(u_int8_t *)c->hdlr_extra;
msg->dst = *(u_int16_t *)c->hdlr_extra;
net_send_queue(c, nb->buf, nb->s_off);
net_send_flush(c);

View File

@ -103,6 +103,7 @@ static struct sock_filter filter_kore[] = {
#if defined(SYS_poll)
KORE_SYSCALL_ALLOW(poll),
#endif
KORE_SYSCALL_ALLOW(ppoll),
KORE_SYSCALL_ALLOW(sendto),
KORE_SYSCALL_ALLOW(accept),
KORE_SYSCALL_ALLOW(sendfile),
@ -154,7 +155,7 @@ static struct sock_filter *seccomp_filter_update(struct sock_filter *,
#define filter_prologue_len KORE_FILTER_LEN(filter_prologue)
#define filter_epilogue_len KORE_FILTER_LEN(filter_epilogue)
static void seccomp_register_violation(struct kore_worker *);
static void seccomp_register_violation(pid_t);
struct filter {
char *name;
@ -313,35 +314,34 @@ kore_seccomp_traceme(void)
}
int
kore_seccomp_trace(struct kore_worker *kw, int status)
kore_seccomp_trace(pid_t pid, int status)
{
int evt;
if (kore_seccomp_tracing == 0)
return (KORE_RESULT_ERROR);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) {
if (kw->tracing == 0) {
kw->tracing = 1;
if (ptrace(PTRACE_SETOPTIONS, kw->pid, NULL,
PTRACE_O_TRACESECCOMP) == -1)
fatal("ptrace: %s", errno_s);
if (ptrace(PTRACE_CONT, kw->pid, NULL, NULL) == -1)
fatal("ptrace: %s", errno_s);
}
return (KORE_RESULT_OK);
}
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
if ((status >> 8) ==
(SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)))
seccomp_register_violation(kw);
if (ptrace(PTRACE_CONT, kw->pid, NULL, NULL) == -1)
if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
PTRACE_O_TRACESECCOMP | PTRACE_O_TRACECLONE |
PTRACE_O_TRACEFORK) == -1)
fatal("ptrace: %s", errno_s);
if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
fatal("ptrace: %s", errno_s);
return (KORE_RESULT_OK);
}
if (WIFSTOPPED(status) && kw->tracing) {
if (ptrace(PTRACE_CONT, kw->pid, NULL, WSTOPSIG(status)) == -1)
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
evt = status >> 8;
if (evt == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)))
seccomp_register_violation(pid);
if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
fatal("ptrace: %s", errno_s);
return (KORE_RESULT_OK);
}
if (WIFSTOPPED(status)) {
if (ptrace(PTRACE_CONT, pid, NULL, WSTOPSIG(status)) == -1)
fatal("ptrace: %s", errno_s);
return (KORE_RESULT_OK);
}
@ -420,16 +420,19 @@ kore_seccomp_syscall_flag(const char *name, int action, int arg, int value)
}
static void
seccomp_register_violation(struct kore_worker *kw)
seccomp_register_violation(pid_t pid)
{
int idx;
struct kore_worker *kw;
struct iovec iov;
struct user_regs_struct regs;
long sysnr;
const char *name;
iov.iov_base = &regs;
iov.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, kw->pid, 1, &iov) == -1)
if (ptrace(PTRACE_GETREGSET, pid, 1, &iov) == -1)
fatal("ptrace: %s", errno_s);
#if SECCOMP_AUDIT_ARCH == AUDIT_ARCH_X86_64
@ -442,8 +445,20 @@ seccomp_register_violation(struct kore_worker *kw)
#error "platform not yet supported"
#endif
kore_log(LOG_INFO, "seccomp violation, worker=%d, syscall=%s",
kw->id, kore_seccomp_syscall_name(sysnr));
name = NULL;
for (idx = 0; idx < worker_count; idx++) {
kw = kore_worker_data(idx);
if (kw->pid == pid) {
name = kore_worker_name(kw->id);
break;
}
}
if (name == NULL)
name = "<child>";
kore_log(LOG_INFO, "seccomp violation, %s pid=%d, syscall=%ld:%s",
name, pid, sysnr, kore_seccomp_syscall_name(sysnr));
}
static struct sock_filter *

View File

@ -17,6 +17,9 @@
#include <sys/types.h>
#include <sys/time.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
@ -47,8 +50,19 @@ static struct {
};
static void fatal_log(const char *, va_list);
static int utils_base64_encode(const void *, size_t, char **,
const char *, int);
static int utils_base64_decode(const char *, u_int8_t **,
size_t *, const char *, int);
static char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char b64_table[] = \
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char b64url_table[] = \
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/* b64_table and b64url_table are the same size. */
#define B64_TABLE_LEN (sizeof(b64_table))
#if defined(KORE_DEBUG)
void
@ -83,20 +97,20 @@ void
kore_log(int prio, const char *fmt, ...)
{
va_list args;
char buf[2048], tmp[32];
const char *name;
char buf[2048];
va_start(args, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (worker != NULL) {
(void)snprintf(tmp, sizeof(tmp), "wrk %d", worker->id);
if (worker->id == KORE_WORKER_KEYMGR)
(void)kore_strlcpy(tmp, "keymgr", sizeof(tmp));
name = kore_worker_name(worker->id);
if (foreground)
printf("[%s]: %s\n", tmp, buf);
printf("%s: %s\n", name, buf);
else
syslog(prio, "[%s]: %s", tmp, buf);
syslog(prio, "%s: %s", name, buf);
} else {
if (foreground)
printf("[parent]: %s\n", buf);
@ -410,135 +424,28 @@ kore_time_ms(void)
return ((u_int64_t)(ts.tv_sec * 1000 + (ts.tv_nsec / 1000000)));
}
int
kore_base64url_encode(const void *data, size_t len, char **out, int flags)
{
return (utils_base64_encode(data, len, out, b64url_table, flags));
}
int
kore_base64_encode(const void *data, size_t len, char **out)
{
u_int8_t n;
size_t nb;
const u_int8_t *ptr;
u_int32_t bytes;
struct kore_buf result;
return (utils_base64_encode(data, len, out, b64_table, 0));
}
nb = 0;
ptr = data;
kore_buf_init(&result, (len / 3) * 4);
while (len > 0) {
if (len > 2) {
nb = 3;
bytes = *ptr++ << 16;
bytes |= *ptr++ << 8;
bytes |= *ptr++;
} else if (len > 1) {
nb = 2;
bytes = *ptr++ << 16;
bytes |= *ptr++ << 8;
} else if (len == 1) {
nb = 1;
bytes = *ptr++ << 16;
} else {
kore_buf_cleanup(&result);
return (KORE_RESULT_ERROR);
}
n = (bytes >> 18) & 0x3f;
kore_buf_append(&result, &(b64table[n]), 1);
n = (bytes >> 12) & 0x3f;
kore_buf_append(&result, &(b64table[n]), 1);
if (nb > 1) {
n = (bytes >> 6) & 0x3f;
kore_buf_append(&result, &(b64table[n]), 1);
if (nb > 2) {
n = bytes & 0x3f;
kore_buf_append(&result, &(b64table[n]), 1);
}
}
len -= nb;
}
switch (nb) {
case 1:
kore_buf_appendf(&result, "==");
break;
case 2:
kore_buf_appendf(&result, "=");
break;
case 3:
break;
default:
kore_buf_cleanup(&result);
return (KORE_RESULT_ERROR);
}
/* result.data gets taken over so no need to cleanup result. */
*out = kore_buf_stringify(&result, NULL);
return (KORE_RESULT_OK);
int
kore_base64url_decode(const char *in, u_int8_t **out, size_t *olen, int flags)
{
return (utils_base64_decode(in, out, olen, b64url_table, flags));
}
int
kore_base64_decode(const char *in, u_int8_t **out, size_t *olen)
{
int i, c;
struct kore_buf *res;
u_int8_t d, n, o;
u_int32_t b, len, idx;
i = 4;
b = 0;
d = 0;
c = 0;
len = strlen(in);
res = kore_buf_alloc(len);
for (idx = 0; idx < len; idx++) {
c = in[idx];
if (c == '=')
break;
for (o = 0; o < sizeof(b64table); o++) {
if (b64table[o] == c) {
d = o;
break;
}
}
if (o == sizeof(b64table)) {
*out = NULL;
kore_buf_free(res);
return (KORE_RESULT_ERROR);
}
b |= (d & 0x3f) << ((i - 1) * 6);
i--;
if (i == 0) {
for (i = 2; i >= 0; i--) {
n = (b >> (8 * i));
kore_buf_append(res, &n, 1);
}
b = 0;
i = 4;
}
}
if (c == '=') {
if (i > 2) {
*out = NULL;
kore_buf_free(res);
return (KORE_RESULT_ERROR);
}
o = i;
for (i = 2; i >= o; i--) {
n = (b >> (8 * i));
kore_buf_append(res, &n, 1);
}
}
*out = kore_buf_release(res, olen);
return (KORE_RESULT_OK);
return (utils_base64_decode(in, out, olen, b64_table, 0));
}
void *
@ -605,6 +512,79 @@ kore_read_line(FILE *fp, char *in, size_t len)
return (p);
}
EVP_PKEY *
kore_rsakey_load(const char *path)
{
FILE *fp;
EVP_PKEY *pkey;
if (access(path, R_OK) == -1)
return (NULL);
if ((fp = fopen(path, "r")) == NULL)
fatalx("%s(%s): %s", __func__, path, errno_s);
if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL)
fatalx("PEM_read_PrivateKey: %s", ssl_errno_s);
fclose(fp);
return (pkey);
}
EVP_PKEY *
kore_rsakey_generate(const char *path)
{
FILE *fp;
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey;
if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
fatalx("EVP_PKEY_CTX_new_id: %s", ssl_errno_s);
if (EVP_PKEY_keygen_init(ctx) <= 0)
fatalx("EVP_PKEY_keygen_init: %s", ssl_errno_s);
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KORE_RSAKEY_BITS) <= 0)
fatalx("EVP_PKEY_CTX_set_rsa_keygen_bits: %s", ssl_errno_s);
pkey = NULL;
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
fatalx("EVP_PKEY_keygen: %s", ssl_errno_s);
if (path != NULL) {
if ((fp = fopen(path, "w")) == NULL)
fatalx("fopen(%s): %s", path, errno_s);
if (!PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL))
fatalx("PEM_write_PrivateKey: %s", ssl_errno_s);
fclose(fp);
}
return (pkey);
}
const char *
kore_worker_name(int id)
{
static char buf[64];
switch (id) {
case KORE_WORKER_KEYMGR:
(void)snprintf(buf, sizeof(buf), "[keymgr]");
break;
case KORE_WORKER_ACME:
(void)snprintf(buf, sizeof(buf), "[acme]");
break;
default:
(void)snprintf(buf, sizeof(buf), "[wrk %d]", id);
break;
}
return (buf);
}
void
fatal(const char *fmt, ...)
{
@ -649,3 +629,169 @@ fatal_log(const char *fmt, va_list args)
printf("%s: %s\n", kore_progname, buf);
}
static int
utils_base64_encode(const void *data, size_t len, char **out,
const char *table, int flags)
{
u_int8_t n;
size_t nb;
const u_int8_t *ptr;
u_int32_t bytes;
struct kore_buf result;
nb = 0;
ptr = data;
kore_buf_init(&result, (len / 3) * 4);
while (len > 0) {
if (len > 2) {
nb = 3;
bytes = *ptr++ << 16;
bytes |= *ptr++ << 8;
bytes |= *ptr++;
} else if (len > 1) {
nb = 2;
bytes = *ptr++ << 16;
bytes |= *ptr++ << 8;
} else if (len == 1) {
nb = 1;
bytes = *ptr++ << 16;
} else {
kore_buf_cleanup(&result);
return (KORE_RESULT_ERROR);
}
n = (bytes >> 18) & 0x3f;
kore_buf_append(&result, &(table[n]), 1);
n = (bytes >> 12) & 0x3f;
kore_buf_append(&result, &(table[n]), 1);
if (nb > 1) {
n = (bytes >> 6) & 0x3f;
kore_buf_append(&result, &(table[n]), 1);
if (nb > 2) {
n = bytes & 0x3f;
kore_buf_append(&result, &(table[n]), 1);
}
}
len -= nb;
}
if (!(flags & KORE_BASE64_RAW)) {
switch (nb) {
case 1:
kore_buf_appendf(&result, "==");
break;
case 2:
kore_buf_appendf(&result, "=");
break;
case 3:
break;
default:
kore_buf_cleanup(&result);
return (KORE_RESULT_ERROR);
}
}
/* result.data gets taken over so no need to cleanup result. */
*out = kore_buf_stringify(&result, NULL);
return (KORE_RESULT_OK);
}
static int
utils_base64_decode(const char *in, u_int8_t **out, size_t *olen,
const char *table, int flags)
{
int i, c;
u_int8_t d, n, o;
struct kore_buf *res, buf;
const char *ptr, *pad;
u_int32_t b, len, plen, idx;
i = 4;
b = 0;
d = 0;
c = 0;
len = strlen(in);
memset(&buf, 0, sizeof(buf));
if (flags & KORE_BASE64_RAW) {
switch (len % 4) {
case 2:
plen = 2;
pad = "==";
break;
case 3:
plen = 1;
pad = "=";
break;
default:
return (KORE_RESULT_ERROR);
}
kore_buf_init(&buf, len + plen);
kore_buf_appendf(&buf, in, len);
kore_buf_appendf(&buf, pad, plen);
len = len + plen;
ptr = (const char *)buf.data;
} else {
ptr = in;
}
res = kore_buf_alloc(len);
for (idx = 0; idx < len; idx++) {
c = ptr[idx];
if (c == '=')
break;
for (o = 0; o < B64_TABLE_LEN; o++) {
if (table[o] == c) {
d = o;
break;
}
}
if (o == B64_TABLE_LEN) {
*out = NULL;
kore_buf_free(res);
kore_buf_cleanup(&buf);
return (KORE_RESULT_ERROR);
}
b |= (d & 0x3f) << ((i - 1) * 6);
i--;
if (i == 0) {
for (i = 2; i >= 0; i--) {
n = (b >> (8 * i));
kore_buf_append(res, &n, 1);
}
b = 0;
i = 4;
}
}
if (c == '=') {
if (i > 2) {
*out = NULL;
kore_buf_free(res);
kore_buf_cleanup(&buf);
return (KORE_RESULT_ERROR);
}
o = i;
for (i = 2; i >= o; i--) {
n = (b >> (8 * i));
kore_buf_append(res, &n, 1);
}
}
kore_buf_cleanup(&buf);
*out = kore_buf_release(res, olen);
return (KORE_RESULT_OK);
}

View File

@ -31,6 +31,10 @@
#include "kore.h"
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
#if !defined(KORE_NO_HTTP)
#include "http.h"
#endif
@ -59,7 +63,7 @@
#define WAIT_ANY (-1)
#endif
#define WORKER_SOLO_COUNT 2
#define WORKER_SOLO_COUNT 3
#define WORKER(id) \
(struct kore_worker *)((u_int8_t *)kore_workers + \
@ -80,8 +84,6 @@ static void worker_accept_avail(struct kore_msg *, const void *);
static void worker_entropy_recv(struct kore_msg *, const void *);
static void worker_keymgr_response(struct kore_msg *, const void *);
static int worker_keymgr_response_verify(struct kore_msg *, const void *,
struct kore_domain **);
static int accept_avail;
static struct kore_worker *kore_workers;
@ -102,15 +104,15 @@ kore_worker_init(void)
{
size_t len;
struct kore_worker *kw;
u_int16_t i, cpu;
u_int16_t idx, id, cpu;
worker_no_lock = 0;
if (worker_count == 0)
worker_count = cpu_count;
/* Account for the keymgr even if we don't end up starting it. */
worker_count += 1;
/* Account for the keymgr/acme even if we don't end up starting it. */
worker_count += 2;
len = sizeof(*accept_lock) +
(sizeof(struct kore_worker) * worker_count);
@ -136,30 +138,41 @@ kore_worker_init(void)
}
/* Setup log buffers. */
for (i = 0; i < worker_count; i++) {
kw = WORKER(i);
for (idx = KORE_WORKER_BASE; idx < worker_count; idx++) {
kw = WORKER(idx);
kw->lb.offset = 0;
}
/* Start keymgr if required. */
if (keymgr_active)
kore_worker_spawn(0, 0);
/* Now start all the workers. */
id = 1;
cpu = 1;
for (i = 1; i < worker_count; i++) {
for (idx = KORE_WORKER_BASE; idx < worker_count; idx++) {
if (cpu >= cpu_count)
cpu = 0;
kore_worker_spawn(i, cpu++);
kore_worker_spawn(idx, id++, cpu++);
}
if (keymgr_active) {
#if defined(KORE_USE_ACME)
/* The ACME process is only started if we need it. */
if (acme_provider) {
kore_worker_spawn(KORE_WORKER_ACME_IDX,
KORE_WORKER_ACME, 0);
}
#endif
/* Now we can start the keymgr. */
kore_worker_spawn(KORE_WORKER_KEYMGR_IDX,
KORE_WORKER_KEYMGR, 0);
}
}
void
kore_worker_spawn(u_int16_t id, u_int16_t cpu)
kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu)
{
struct kore_worker *kw;
kw = WORKER(id);
kw = WORKER(idx);
kw->id = id;
kw->cpu = cpu;
kw->has_lock = 0;
@ -198,7 +211,7 @@ kore_worker_shutdown(void)
struct kore_worker *kw;
pid_t pid;
int status;
u_int16_t id, done;
u_int16_t idx, done;
if (!kore_quiet) {
kore_log(LOG_NOTICE,
@ -206,15 +219,15 @@ kore_worker_shutdown(void)
}
for (;;) {
for (id = 0; id < worker_count; id++) {
kw = WORKER(id);
for (idx = 0; idx < worker_count; idx++) {
kw = WORKER(idx);
if (kw->pid != 0) {
pid = waitpid(kw->pid, &status, 0);
if (pid == -1)
continue;
#if defined(__linux__)
kore_seccomp_trace(kw, status);
kore_seccomp_trace(kw->pid, status);
#endif
if (WIFEXITED(status)) {
@ -229,8 +242,8 @@ kore_worker_shutdown(void)
}
done = 0;
for (id = 0; id < worker_count; id++) {
kw = WORKER(id);
for (idx = 0; idx < worker_count; idx++) {
kw = WORKER(idx);
if (kw->pid == 0)
done++;
}
@ -248,11 +261,11 @@ kore_worker_shutdown(void)
void
kore_worker_dispatch_signal(int sig)
{
u_int16_t id;
u_int16_t idx;
struct kore_worker *kw;
for (id = 0; id < worker_count; id++) {
kw = WORKER(id);
for (idx = 0; idx < worker_count; idx++) {
kw = WORKER(idx);
if (kill(kw->pid, sig) == -1) {
kore_debug("kill(%d, %d): %s", kw->pid, sig, errno_s);
}
@ -329,7 +342,6 @@ void
kore_worker_entry(struct kore_worker *kw)
{
struct kore_runtime_call *rcall;
char buf[16];
u_int64_t last_seed;
int quit, had_lock;
u_int64_t netwait, now, next_prune;
@ -340,10 +352,7 @@ kore_worker_entry(struct kore_worker *kw)
kore_seccomp_traceme();
#endif
(void)snprintf(buf, sizeof(buf), "[wrk %d]", kw->id);
if (kw->id == KORE_WORKER_KEYMGR)
(void)snprintf(buf, sizeof(buf), "[keymgr]");
kore_platform_proctitle(buf);
kore_platform_proctitle(kore_worker_name(kw->id));
if (worker_set_affinity == 1)
kore_platform_worker_setcpu(kw);
@ -357,6 +366,13 @@ kore_worker_entry(struct kore_worker *kw)
exit(0);
}
#if defined(KORE_USE_ACME)
if (kw->id == KORE_WORKER_ACME) {
kore_acme_run();
exit(0);
}
#endif
net_init();
kore_connection_init();
kore_platform_event_init();
@ -394,6 +410,12 @@ kore_worker_entry(struct kore_worker *kw)
kore_msg_send(KORE_WORKER_KEYMGR,
KORE_MSG_CERTIFICATE_REQ, NULL, 0);
}
#if defined(KORE_USE_ACME)
kore_msg_register(KORE_ACME_CHALLENGE_SET_CERT,
worker_keymgr_response);
kore_msg_register(KORE_ACME_CHALLENGE_CLEAR_CERT,
worker_keymgr_response);
#endif
}
kore_msg_register(KORE_MSG_ACCEPT_AVAILABLE, worker_accept_avail);
@ -575,23 +597,79 @@ kore_worker_make_busy(void)
}
}
int
kore_worker_keymgr_response_verify(struct kore_msg *msg, const void *data,
struct kore_domain **out)
{
struct kore_server *srv;
struct kore_domain *dom;
const struct kore_x509_msg *req;
if (msg->length < sizeof(*req)) {
kore_log(LOG_WARNING,
"short keymgr message (%zu)", msg->length);
return (KORE_RESULT_ERROR);
}
req = (const struct kore_x509_msg *)data;
if (msg->length != (sizeof(*req) + req->data_len)) {
kore_log(LOG_WARNING,
"invalid keymgr payload (%zu)", msg->length);
return (KORE_RESULT_ERROR);
}
if (req->domain[KORE_DOMAINNAME_LEN] != '\0') {
kore_log(LOG_WARNING, "domain not NUL-terminated");
return (KORE_RESULT_ERROR);
}
if (out == NULL)
return (KORE_RESULT_OK);
LIST_FOREACH(srv, &kore_servers, list) {
dom = NULL;
if (srv->tls == 0)
continue;
TAILQ_FOREACH(dom, &srv->domains, list) {
if (!strcmp(dom->domain, req->domain))
break;
}
if (dom != NULL)
break;
}
if (dom == NULL) {
kore_log(LOG_WARNING,
"got keymgr response for domain that does not exist");
return (KORE_RESULT_ERROR);
}
*out = dom;
return (KORE_RESULT_OK);
}
static void
worker_reaper(pid_t pid, int status)
{
u_int16_t id;
u_int16_t idx;
struct kore_worker *kw;
const char *func;
for (id = 0; id < worker_count; id++) {
kw = WORKER(id);
#if defined(__linux__)
if (kore_seccomp_trace(pid, status))
return;
#endif
for (idx = 0; idx < worker_count; idx++) {
kw = WORKER(idx);
if (kw->pid != pid)
continue;
#if defined(__linux__)
if (kore_seccomp_trace(kw, status))
break;
#endif
if (!kore_quiet) {
kore_log(LOG_NOTICE,
"worker %d (%d) exited with status %d",
@ -619,8 +697,10 @@ worker_reaper(pid_t pid, int status)
}
#endif
if (id == KORE_WORKER_KEYMGR) {
kore_log(LOG_CRIT, "keymgr gone, stopping");
if (kw->id == KORE_WORKER_KEYMGR ||
kw->id == KORE_WORKER_ACME) {
kore_log(LOG_CRIT,
"keymgr or acme process gone, stopping");
kw->pid = 0;
if (raise(SIGTERM) != 0) {
kore_log(LOG_WARNING,
@ -657,7 +737,7 @@ worker_reaper(pid_t pid, int status)
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_worker_spawn(idx, kw->id, kw->cpu);
kore_msg_parent_add(kw);
break;
@ -769,74 +849,45 @@ worker_keymgr_response(struct kore_msg *msg, const void *data)
struct kore_domain *dom;
const struct kore_x509_msg *req;
if (!worker_keymgr_response_verify(msg, data, &dom))
if (!kore_worker_keymgr_response_verify(msg, data, &dom))
return;
req = (const struct kore_x509_msg *)data;
switch (msg->id) {
case KORE_MSG_CERTIFICATE:
kore_domain_tlsinit(dom, req->data, req->data_len);
kore_domain_tlsinit(dom, KORE_PEM_CERT_CHAIN,
req->data, req->data_len);
break;
case KORE_MSG_CRL:
kore_domain_crl_add(dom, req->data, req->data_len);
break;
#if defined(KORE_USE_ACME)
case KORE_ACME_CHALLENGE_SET_CERT:
if (dom->ssl_ctx == NULL) {
kore_domain_tlsinit(dom, KORE_DER_CERT_DATA,
req->data, req->data_len);
}
kore_free(dom->acme_cert);
dom->acme_cert_len = req->data_len;
dom->acme_cert = kore_calloc(1, req->data_len);
memcpy(dom->acme_cert, req->data, req->data_len);
kore_log(LOG_NOTICE, "[%s] tls-alpn-01 challenge active",
dom->domain);
dom->acme_challenge = 1;
break;
case KORE_ACME_CHALLENGE_CLEAR_CERT:
dom->acme_cert_len = 0;
dom->acme_challenge = 0;
kore_free(dom->acme_cert);
kore_log(LOG_NOTICE, "[%s] tls-alpn-01 challenge disabled",
dom->domain);
break;
#endif
default:
kore_log(LOG_WARNING, "unknown keymgr request %u", msg->id);
break;
}
}
static int
worker_keymgr_response_verify(struct kore_msg *msg, const void *data,
struct kore_domain **out)
{
struct kore_server *srv;
struct kore_domain *dom;
const struct kore_x509_msg *req;
if (msg->length < sizeof(*req)) {
kore_log(LOG_WARNING,
"short keymgr message (%zu)", msg->length);
return (KORE_RESULT_ERROR);
}
req = (const struct kore_x509_msg *)data;
if (msg->length != (sizeof(*req) + req->data_len)) {
kore_log(LOG_WARNING,
"invalid keymgr payload (%zu)", msg->length);
return (KORE_RESULT_ERROR);
}
if (req->domain_len > KORE_DOMAINNAME_LEN) {
kore_log(LOG_WARNING,
"invalid keymgr domain (%u)",
req->domain_len);
return (KORE_RESULT_ERROR);
}
LIST_FOREACH(srv, &kore_servers, list) {
dom = NULL;
if (srv->tls == 0)
continue;
TAILQ_FOREACH(dom, &srv->domains, list) {
if (!strncmp(dom->domain, req->domain, req->domain_len))
break;
}
if (dom != NULL)
break;
}
if (dom == NULL) {
kore_log(LOG_WARNING,
"got keymgr response for domain that does not exist");
return (KORE_RESULT_ERROR);
}
*out = dom;
return (KORE_RESULT_OK);
}