Compare commits

...

32 Commits
master ... acme

Author SHA1 Message Date
Joris Vink 9a59f6833a reduce order start time to 1 second. 2019-11-06 14:26:36 +01:00
Joris Vink 3d1145dc50 adjustments to seccomp for musl based systems 2019-11-06 14:20:36 +01:00
Joris Vink bb159da725 set a default acme provider (letsencrypt) 2019-11-06 14:01:28 +01:00
Joris Vink c55ec5c0d8 allow lseek in keymgr 2019-11-06 13:29:46 +01:00
Joris Vink 703482bc10 Improve linux acme support.
- Adjusted seccomp rules for arm64.
- Properly log seccomp violations for clones or forks or our processes.
2019-11-06 12:11:31 +01:00
Joris Vink 0d4114811a Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-11-06 11:58:55 +01:00
Joris Vink f8524392e8 more seccomp adjustments in acme process 2019-11-05 13:20:03 +01:00
Joris Vink 1a0fb72923 adjust seccomp rules for newer platforms 2019-11-05 13:18:28 +01:00
Joris Vink 449fffca44 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-11-05 13:17:06 +01:00
Joris Vink bb37f7e5ec add seccomp rules and other small cleanups 2019-11-04 21:27:40 +01:00
Joris Vink 313133f252 small improvements 2019-11-04 11:10:14 +01:00
Joris Vink 3e06668d3f allow empty hdlr_extra for msg 2019-11-04 11:10:02 +01:00
Joris Vink 70083add32 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-11-03 22:34:57 +01:00
Joris Vink c4b82220e4 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-11-03 12:35:01 +01:00
Joris Vink 0f13606967 fix pledges and add unveil on openbsd 2019-11-01 12:43:09 +01:00
Joris Vink a34f4597b4 convert x509 notAfter times ourselves.
ASN1_TIME_diff() would've been nice to use but some openssl forks
completely lack it and provide no sensible way of doing this.
2019-11-01 11:20:24 +01:00
Joris Vink 6812cd0a12 make renewals work 2019-11-01 09:18:01 +01:00
Joris Vink a9864c9ff7 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-31 14:03:57 +01:00
Joris Vink 7e41def497 we have certs. 2019-10-30 00:14:37 +01:00
Joris Vink dab77e9b52 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-29 19:32:44 +01:00
Joris Vink 8c836cf9d0 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-28 12:48:27 +01:00
Joris Vink 2516abdfa2 update for latest master changes 2019-10-28 12:45:08 +01:00
Joris Vink e4e8093bc3 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-28 12:35:40 +01:00
Joris Vink 2377dee21a Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-28 12:19:19 +01:00
Joris Vink 58678ff0ad make sure this works with latest openssl 2019-10-28 09:58:58 +01:00
Joris Vink 1a9197ffeb more progress 2019-10-28 09:51:03 +01:00
Joris Vink bfcc4afe48 Merge branch 'master' of mooncake.coders.se:/home/git/kore into acme 2019-10-27 21:22:58 +01:00
Joris Vink f2882643ce save work 2019-10-27 21:22:53 +01:00
Joris Vink 21696a0f2e add scaffolding code for alpn challenge 2019-10-25 21:51:55 +02:00
Joris Vink 4cd64cd06d add error type and detail to authz error logs 2019-10-25 20:41:24 +02:00
Joris Vink 82709ec2cc get all the things up to challenges working 2019-10-25 19:40:36 +02:00
Joris Vink 0a958de9c0 get stuff committed for acme 2019-10-24 23:30:38 +02:00
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);
}