Merge branch 'master' into 3.0.0-releng

This commit is contained in:
Joris Vink 2019-01-14 13:05:42 +01:00
commit 06897a3a37
6 changed files with 254 additions and 80 deletions

View File

@ -40,6 +40,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
@ -410,7 +411,9 @@ struct kore_domain {
#if !defined(KORE_NO_TLS)
char *cafile;
char *crlfile;
time_t crl_mtime;
char *certfile;
time_t cert_mtime;
char *certkey;
SSL_CTX *ssl_ctx;
int x509_verify_depth;
@ -494,6 +497,7 @@ struct kore_timer {
#define KORE_MSG_ENTROPY_RESP 6
#define KORE_MSG_CERTIFICATE 7
#define KORE_MSG_CERTIFICATE_REQ 8
#define KORE_MSG_CRL 9
/* Predefined message targets. */
#define KORE_MSG_PARENT 1000
@ -746,6 +750,7 @@ void kore_domain_load_crl(void);
void kore_domain_keymgr_init(void);
void kore_domain_callback(void (*cb)(struct kore_domain *));
void kore_domain_tlsinit(struct kore_domain *, 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(const char *, const char *,
const char *, const char *, int);

View File

@ -164,14 +164,18 @@ static PyObject *pysocket_send(struct pysocket *, PyObject *);
static PyObject *pysocket_recv(struct pysocket *, PyObject *);
static PyObject *pysocket_close(struct pysocket *, PyObject *);
static PyObject *pysocket_accept(struct pysocket *, PyObject *);
static PyObject *pysocket_sendto(struct pysocket *, PyObject *);
static PyObject *pysocket_connect(struct pysocket *, PyObject *);
static PyObject *pysocket_recvfrom(struct pysocket *, PyObject *);
static PyMethodDef pysocket_methods[] = {
METHOD("recv", pysocket_recv, METH_VARARGS),
METHOD("send", pysocket_send, METH_VARARGS),
METHOD("close", pysocket_close, METH_NOARGS),
METHOD("accept", pysocket_accept, METH_NOARGS),
METHOD("sendto", pysocket_sendto, METH_VARARGS),
METHOD("connect", pysocket_connect, METH_VARARGS),
METHOD("recvfrom", pysocket_recvfrom, METH_VARARGS),
METHOD(NULL, NULL, -1),
};
@ -191,6 +195,8 @@ static PyTypeObject pysocket_type = {
#define PYSOCKET_TYPE_CONNECT 2
#define PYSOCKET_TYPE_RECV 3
#define PYSOCKET_TYPE_SEND 4
#define PYSOCKET_TYPE_RECVFROM 5
#define PYSOCKET_TYPE_SENDTO 6
struct pysocket_data {
struct kore_event evt;
@ -202,6 +208,7 @@ struct pysocket_data {
int state;
size_t length;
struct kore_buf buffer;
struct sockaddr_in sendaddr;
struct pysocket *socket;
};

View File

@ -56,7 +56,6 @@ int tls_version = KORE_TLS_VERSION_BOTH;
#if !defined(KORE_NO_TLS)
static BIO *domain_bio_mem(const void *, size_t);
static int domain_x509_verify(int, X509_STORE_CTX *);
static void domain_load_crl(struct kore_domain *);
static X509 *domain_load_certificate_chain(SSL_CTX *, const void *, size_t);
static void keymgr_init(void);
@ -211,6 +210,9 @@ kore_domain_new(char *domain)
dom->ssl_ctx = NULL;
dom->certfile = NULL;
dom->crlfile = NULL;
dom->crl_mtime = 0;
dom->cert_mtime = 0;
dom->x509_verify_depth = 1;
#endif
dom->domain = kore_strdup(domain);
@ -436,6 +438,57 @@ kore_domain_tlsinit(struct kore_domain *dom, const void *pem, size_t pemlen)
X509_free(x509);
}
void
kore_domain_crl_add(struct kore_domain *dom, const void *pem, size_t pemlen)
{
int err;
BIO *in;
X509_CRL *crl;
X509_STORE *store;
ERR_clear_error();
in = domain_bio_mem(pem, pemlen);
if ((store = SSL_CTX_get_cert_store(dom->ssl_ctx)) == NULL) {
BIO_free(in);
kore_log(LOG_ERR, "SSL_CTX_get_cert_store(): %s", ssl_errno_s);
return;
}
for (;;) {
crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
if (crl == NULL) {
err = ERR_GET_REASON(ERR_peek_last_error());
if (err == PEM_R_NO_START_LINE) {
ERR_clear_error();
break;
}
kore_log(LOG_WARNING, "failed to read CRL %s: %s",
dom->crlfile, ssl_errno_s);
continue;
}
if (!X509_STORE_add_crl(store, crl)) {
err = ERR_GET_REASON(ERR_peek_last_error());
if (err == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
X509_CRL_free(crl);
continue;
}
kore_log(LOG_WARNING, "failed to add CRL %s: %s",
dom->crlfile, ssl_errno_s);
X509_CRL_free(crl);
continue;
}
}
BIO_free(in);
X509_STORE_set_flags(store,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
}
#endif
void
@ -499,17 +552,6 @@ kore_domain_closelogs(void)
}
}
void
kore_domain_load_crl(void)
{
#if !defined(KORE_NO_TLS)
struct kore_domain *dom;
TAILQ_FOREACH(dom, &domains, list)
domain_load_crl(dom);
#endif
}
void
kore_domain_keymgr_init(void)
{
@ -519,38 +561,6 @@ kore_domain_keymgr_init(void)
#endif
}
#if !defined(KORE_NO_TLS)
static void
domain_load_crl(struct kore_domain *dom)
{
X509_STORE *store;
if (dom->cafile == NULL)
return;
if (dom->crlfile == NULL) {
kore_log(LOG_WARNING, "WARNING: no CRL configured for '%s'",
dom->domain);
return;
}
ERR_clear_error();
if ((store = SSL_CTX_get_cert_store(dom->ssl_ctx)) == NULL) {
kore_log(LOG_ERR, "SSL_CTX_get_cert_store(): %s", ssl_errno_s);
return;
}
if (!X509_STORE_load_locations(store, dom->crlfile, NULL)) {
kore_log(LOG_ERR, "X509_STORE_load_locations(): %s",
ssl_errno_s);
return;
}
X509_STORE_set_flags(store,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
}
#endif
#if !defined(KORE_NO_TLS)
static void
keymgr_init(void)

View File

@ -72,6 +72,8 @@ static void keymgr_msg_recv(struct kore_msg *, const void *);
static void keymgr_entropy_request(struct kore_msg *, const void *);
static void keymgr_certificate_request(struct kore_msg *, const void *);
static void keymgr_submit_certificates(struct kore_domain *, u_int16_t);
static void keymgr_submit_file(u_int8_t, struct kore_domain *,
const char *, u_int16_t, time_t *, int);
static void keymgr_rsa_encrypt(struct kore_msg *, const void *,
struct key *);
@ -180,7 +182,7 @@ keymgr_reload(void)
{
struct kore_domain *dom;
kore_log(LOG_INFO, "(re)loading certificates and keys");
kore_log(LOG_INFO, "(re)loading certificates, keys and CRLs");
kore_keymgr_cleanup(0);
TAILQ_INIT(&keys);
@ -194,6 +196,19 @@ keymgr_reload(void)
static void
keymgr_submit_certificates(struct kore_domain *dom, u_int16_t dst)
{
keymgr_submit_file(KORE_MSG_CERTIFICATE,
dom, dom->certfile, dst, &dom->cert_mtime, 0);
if (dom->crlfile != NULL) {
keymgr_submit_file(KORE_MSG_CRL,
dom, dom->crlfile, dst, &dom->crl_mtime, 1);
}
}
static void
keymgr_submit_file(u_int8_t id, struct kore_domain *dom,
const char *file, u_int16_t dst, time_t *mtime, int can_fail)
{
int fd;
struct stat st;
@ -202,18 +217,30 @@ keymgr_submit_certificates(struct kore_domain *dom, u_int16_t dst)
struct kore_x509_msg *msg;
u_int8_t *payload;
if ((fd = open(dom->certfile, O_RDONLY)) == -1)
fatal("open(%s): %s", dom->certfile, errno_s);
if (fstat(fd, &st) == -1)
fatal("stat(%s): %s", dom->certfile, errno_s);
if (!S_ISREG(st.st_mode))
fatal("%s is not a file", dom->certfile);
if ((fd = open(file, O_RDONLY)) == -1) {
if (errno == ENOENT && can_fail)
return;
fatal("open(%s): %s", file, errno_s);
}
if (st.st_size <= 0 || st.st_size > (1024 * 1024 * 5)) {
fatal("%s length is not valid (%jd)", dom->certfile,
if (fstat(fd, &st) == -1)
fatal("stat(%s): %s", file, errno_s);
if (!S_ISREG(st.st_mode))
fatal("%s is not a file", file);
if (st.st_size <= 0 || st.st_size > (1024 * 1024 * 10)) {
fatal("%s length is not valid (%jd)", file,
(intmax_t)st.st_size);
}
if (st.st_mtime == *mtime) {
close(fd);
return;
}
*mtime = st.st_mtime;
len = sizeof(*msg) + st.st_size;
payload = kore_calloc(1, len);
@ -225,15 +252,17 @@ keymgr_submit_certificates(struct kore_domain *dom, u_int16_t dst)
msg->data_len = st.st_size;
ret = read(fd, &msg->data[0], msg->data_len);
if (ret == -1)
fatal("failed to read from %s: %s", file, errno_s);
if (ret == 0)
fatal("eof while reading %s", dom->certfile);
fatal("eof while reading %s", file);
if ((size_t)ret != msg->data_len) {
fatal("bad read on %s: expected %zu, got %zd",
dom->certfile, msg->data_len, ret);
file, msg->data_len, ret);
}
kore_msg_send(dst, KORE_MSG_CERTIFICATE, payload, len);
kore_msg_send(dst, id, payload, len);
kore_free(payload);
close(fd);
}

View File

@ -1617,6 +1617,40 @@ pysocket_send(struct pysocket *sock, PyObject *args)
return (pysocket_op_create(sock, PYSOCKET_TYPE_SEND, buf.buf, buf.len));
}
static PyObject *
pysocket_sendto(struct pysocket *sock, PyObject *args)
{
Py_buffer buf;
struct pysocket_op *op;
const char *ip;
PyObject *ret;
int port;
if (sock->family != AF_INET) {
PyErr_SetString(PyExc_RuntimeError,
"sendto only supported on AF_INET sockets");
return (NULL);
}
if (!PyArg_ParseTuple(args, "siy*", &ip, &port, &buf))
return (NULL);
if (port <= 0 || port >= USHRT_MAX) {
PyErr_SetString(PyExc_RuntimeError, "invalid port");
return (NULL);
}
ret = pysocket_op_create(sock, PYSOCKET_TYPE_SENDTO, buf.buf, buf.len);
op = (struct pysocket_op *)ret;
op->data.sendaddr.sin_family = AF_INET;
op->data.sendaddr.sin_port = htons(port);
op->data.sendaddr.sin_addr.s_addr = inet_addr(ip);
return (ret);
}
static PyObject *
pysocket_recv(struct pysocket *sock, PyObject *args)
{
@ -1628,6 +1662,23 @@ pysocket_recv(struct pysocket *sock, PyObject *args)
return (pysocket_op_create(sock, PYSOCKET_TYPE_RECV, NULL, len));
}
static PyObject *
pysocket_recvfrom(struct pysocket *sock, PyObject *args)
{
Py_ssize_t len;
if (sock->family != AF_INET) {
PyErr_SetString(PyExc_RuntimeError,
"recvfrom only supported on AF_INET sockets");
return (NULL);
}
if (!PyArg_ParseTuple(args, "n", &len))
return (NULL);
return (pysocket_op_create(sock, PYSOCKET_TYPE_RECVFROM, NULL, len));
}
static PyObject *
pysocket_accept(struct pysocket *sock, PyObject *args)
{
@ -1708,9 +1759,11 @@ pysocket_op_dealloc(struct pysocket_op *op)
switch (op->data.type) {
case PYSOCKET_TYPE_RECV:
case PYSOCKET_TYPE_ACCEPT:
case PYSOCKET_TYPE_RECVFROM:
kore_platform_disable_read(op->data.fd);
break;
case PYSOCKET_TYPE_SEND:
case PYSOCKET_TYPE_SENDTO:
case PYSOCKET_TYPE_CONNECT:
kore_platform_disable_write(op->data.fd);
break;
@ -1720,6 +1773,7 @@ pysocket_op_dealloc(struct pysocket_op *op)
#endif
if (op->data.type == PYSOCKET_TYPE_RECV ||
op->data.type == PYSOCKET_TYPE_RECVFROM ||
op->data.type == PYSOCKET_TYPE_SEND)
kore_buf_cleanup(&op->data.buffer);
@ -1768,11 +1822,13 @@ pysocket_op_create(struct pysocket *sock, int type, const void *ptr, size_t len)
switch (type) {
case PYSOCKET_TYPE_RECV:
case PYSOCKET_TYPE_RECVFROM:
op->data.evt.flags |= KORE_EVENT_READ;
kore_buf_init(&op->data.buffer, len);
kore_platform_schedule_read(op->data.fd, &op->data);
break;
case PYSOCKET_TYPE_SEND:
case PYSOCKET_TYPE_SENDTO:
op->data.evt.flags |= KORE_EVENT_WRITE;
kore_buf_init(&op->data.buffer, len);
kore_buf_append(&op->data.buffer, ptr, len);
@ -1832,9 +1888,11 @@ pysocket_op_iternext(struct pysocket_op *op)
ret = pysocket_async_accept(op);
break;
case PYSOCKET_TYPE_RECV:
case PYSOCKET_TYPE_RECVFROM:
ret = pysocket_async_recv(op);
break;
case PYSOCKET_TYPE_SEND:
case PYSOCKET_TYPE_SENDTO:
ret = pysocket_async_send(op);
break;
default:
@ -1907,16 +1965,27 @@ static PyObject *
pysocket_async_recv(struct pysocket_op *op)
{
ssize_t ret;
const char *ptr;
PyObject *bytes;
u_int16_t port;
socklen_t socklen;
const char *ptr, *ip;
PyObject *bytes, *result, *tuple;
if (!(op->data.evt.flags & KORE_EVENT_READ)) {
Py_RETURN_NONE;
}
for (;;) {
ret = read(op->data.fd, op->data.buffer.data,
op->data.buffer.length);
if (op->data.type == PYSOCKET_TYPE_RECV) {
ret = read(op->data.fd, op->data.buffer.data,
op->data.buffer.length);
} else {
socklen = sizeof(op->data.sendaddr);
ret = recvfrom(op->data.fd, op->data.buffer.data,
op->data.buffer.length, 0,
(struct sockaddr *)&op->data.sendaddr,
&socklen);
}
if (ret == -1) {
if (errno == EINTR)
continue;
@ -1931,19 +2000,36 @@ pysocket_async_recv(struct pysocket_op *op)
break;
}
if (ret == 0) {
if (op->data.type == PYSOCKET_TYPE_RECV && ret == 0) {
PyErr_SetNone(PyExc_StopIteration);
return (NULL);
}
ptr = (const char *)op->data.buffer.data;
if ((bytes = PyBytes_FromStringAndSize(ptr, ret)) == NULL)
return (NULL);
bytes = PyBytes_FromStringAndSize(ptr, ret);
if (bytes != NULL) {
if (op->data.type == PYSOCKET_TYPE_RECV) {
PyErr_SetObject(PyExc_StopIteration, bytes);
Py_DECREF(bytes);
return (NULL);
}
port = ntohs(op->data.sendaddr.sin_port);
ip = inet_ntoa(op->data.sendaddr.sin_addr);
if ((tuple = Py_BuildValue("(sHN)", ip, port, bytes)) == NULL)
return (NULL);
result = PyObject_CallFunctionObjArgs(PyExc_StopIteration, tuple, NULL);
if (result == NULL) {
Py_DECREF(tuple);
return (NULL);
}
PyErr_SetObject(PyExc_StopIteration, result);
Py_DECREF(result);
return (NULL);
}
@ -1957,9 +2043,18 @@ pysocket_async_send(struct pysocket_op *op)
}
for (;;) {
ret = write(op->data.fd,
op->data.buffer.data + op->data.buffer.offset,
op->data.buffer.length - op->data.buffer.offset);
if (op->data.type == PYSOCKET_TYPE_SEND) {
ret = write(op->data.fd,
op->data.buffer.data + op->data.buffer.offset,
op->data.buffer.length - op->data.buffer.offset);
} else {
ret = sendto(op->data.fd,
op->data.buffer.data + op->data.buffer.offset,
op->data.buffer.length - op->data.buffer.offset,
0, (const struct sockaddr *)&op->data.sendaddr,
sizeof(op->data.sendaddr));
}
if (ret == -1) {
if (errno == EINTR)
continue;

View File

@ -77,7 +77,9 @@ static inline int worker_acceptlock_release(u_int64_t);
#if !defined(KORE_NO_TLS)
static void worker_entropy_recv(struct kore_msg *, const void *);
static void worker_certificate_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 **);
#endif
static u_int64_t next_lock;
@ -348,7 +350,6 @@ kore_worker_entry(struct kore_worker *kw)
#endif
kore_timer_init();
kore_fileref_init();
kore_domain_load_crl();
kore_domain_keymgr_init();
quit = 0;
@ -367,8 +368,9 @@ kore_worker_entry(struct kore_worker *kw)
#if !defined(KORE_NO_TLS)
last_seed = 0;
kore_msg_register(KORE_MSG_CRL, worker_keymgr_response);
kore_msg_register(KORE_MSG_ENTROPY_RESP, worker_entropy_recv);
kore_msg_register(KORE_MSG_CERTIFICATE, worker_certificate_recv);
kore_msg_register(KORE_MSG_CERTIFICATE, worker_keymgr_response);
if (worker->restarted) {
kore_msg_send(KORE_WORKER_KEYMGR,
KORE_MSG_CERTIFICATE_REQ, NULL, 0);
@ -711,29 +713,54 @@ worker_entropy_recv(struct kore_msg *msg, const void *data)
}
static void
worker_certificate_recv(struct kore_msg *msg, const void *data)
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))
return;
req = (const struct kore_x509_msg *)data;
switch (msg->id) {
case KORE_MSG_CERTIFICATE:
kore_domain_tlsinit(dom, req->data, req->data_len);
break;
case KORE_MSG_CRL:
kore_domain_crl_add(dom, req->data, req->data_len);
break;
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_domain *dom;
const struct kore_x509_msg *req;
if (msg->length < sizeof(*req)) {
kore_log(LOG_WARNING,
"short KORE_MSG_CERTIFICATE message (%zu)", msg->length);
return;
"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 KORE_MSG_CERTIFICATE payload (%zu)", msg->length);
return;
"invalid keymgr payload (%zu)", msg->length);
return (KORE_RESULT_ERROR);
}
if (req->domain_len > KORE_DOMAINNAME_LEN) {
kore_log(LOG_WARNING,
"invalid KORE_MSG_CERTIFICATE domain (%u)",
"invalid keymgr domain (%u)",
req->domain_len);
return;
return (KORE_RESULT_ERROR);
}
dom = NULL;
@ -744,11 +771,12 @@ worker_certificate_recv(struct kore_msg *msg, const void *data)
if (dom == NULL) {
kore_log(LOG_WARNING,
"got KORE_MSG_CERTIFICATE for domain that does not exist");
return;
"got keymgr response for domain that does not exist");
return (KORE_RESULT_ERROR);
}
/* reinitialize the domain TLS context. */
kore_domain_tlsinit(dom, req->data, req->data_len);
*out = dom;
return (KORE_RESULT_OK);
}
#endif