Compare commits

...

11 Commits

Author SHA1 Message Date
Omar Polo 822125ca3f add more endian.h macros implementation for macos 2024-01-07 19:01:40 +00:00
Omar Polo 08e6d6ed7a mark private function as static 2024-01-07 18:59:10 +00:00
Omar Polo 0c5dd8ffe9 remove explicit #include endian.h
unfortunately that's not portable.  config.h will include the right
stuff however.
2024-01-07 18:58:26 +00:00
Omar Polo ebfc578491 sync libtls 2024-01-07 18:52:51 +00:00
Omar Polo 12eb29d878 sync imsg 2024-01-07 18:27:41 +00:00
Omar Polo b8537c1c54 add sentence to contrib.gmi 2024-01-07 17:25:15 +00:00
Omar Polo 59953b20b2 disable -Werror=use-after free for CI
gcc' use after free detection is busted and sees one in vis.c where
it's not possible.
2024-01-07 16:35:02 +00:00
Omar Polo acc862155d update the quistart for gmid 2.0 2024-01-07 16:22:43 +00:00
Omar Polo dad248f4cf improve the home page for upcoming 2.0 2024-01-05 20:14:02 +00:00
Omar Polo 6660c0bd41 update faqs 2024-01-05 20:06:02 +00:00
Omar Polo ac6c76f8a8 fix link 2024-01-05 19:13:59 +00:00
19 changed files with 1168 additions and 385 deletions

View File

@ -1,9 +1,12 @@
# gcc' -Werror=use-after-free gets tripped by vis.c: it sees a use
# after free where it's not possible and breaks the CI.
linux_amd64_task:
container:
image: alpine:latest
test_script:
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
- make
- make regress REGRESS_HOST="*"
@ -12,7 +15,7 @@ linux_arm_task:
image: alpine:latest
test_script:
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
- make
- make regress REGRESS_HOST="*"

View File

@ -1,6 +1,7 @@
/* $OpenBSD: imsg-buffer.c,v 1.16 2023/06/19 17:19:50 claudio Exp $ */
/* $OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $ */
/*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -24,6 +25,7 @@
#include <limits.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -61,7 +63,7 @@ ibuf_dynamic(size_t len, size_t max)
{
struct ibuf *buf;
if (max < len) {
if (max == 0 || max < len) {
errno = EINVAL;
return (NULL);
}
@ -106,7 +108,7 @@ ibuf_reserve(struct ibuf *buf, size_t len)
{
void *b;
if (len > SIZE_MAX - buf->wpos) {
if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
errno = ERANGE;
return (NULL);
}
@ -117,7 +119,6 @@ ibuf_reserve(struct ibuf *buf, size_t len)
b = buf->buf + buf->wpos;
buf->wpos += len;
memset(b, 0, len);
return (b);
}
@ -133,10 +134,17 @@ ibuf_add(struct ibuf *buf, const void *data, size_t len)
return (0);
}
int
ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
{
return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
}
/* remove after tree is converted */
int
ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
{
return ibuf_add(buf, from->buf, from->wpos);
return ibuf_add_ibuf(buf, from);
}
int
@ -185,6 +193,38 @@ ibuf_add_n64(struct ibuf *buf, uint64_t value)
return ibuf_add(buf, &value, sizeof(value));
}
int
ibuf_add_h16(struct ibuf *buf, uint64_t value)
{
uint16_t v;
if (value > UINT16_MAX) {
errno = EINVAL;
return (-1);
}
v = value;
return ibuf_add(buf, &v, sizeof(v));
}
int
ibuf_add_h32(struct ibuf *buf, uint64_t value)
{
uint32_t v;
if (value > UINT32_MAX) {
errno = EINVAL;
return (-1);
}
v = value;
return ibuf_add(buf, &v, sizeof(v));
}
int
ibuf_add_h64(struct ibuf *buf, uint64_t value)
{
return ibuf_add(buf, &value, sizeof(value));
}
int
ibuf_add_zero(struct ibuf *buf, size_t len)
{
@ -192,19 +232,21 @@ ibuf_add_zero(struct ibuf *buf, size_t len)
if ((b = ibuf_reserve(buf, len)) == NULL)
return (-1);
memset(b, 0, len);
return (0);
}
void *
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
{
/* only allowed to seek in already written parts */
if (len > SIZE_MAX - pos || pos + len > buf->wpos) {
/* only allow seeking between rpos and wpos */
if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
ibuf_size(buf) < pos + len) {
errno = ERANGE;
return (NULL);
}
return (buf->buf + pos);
return (buf->buf + buf->rpos + pos);
}
int
@ -265,39 +307,201 @@ ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
return (ibuf_set(buf, pos, &value, sizeof(value)));
}
int
ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
{
uint16_t v;
if (value > UINT16_MAX) {
errno = EINVAL;
return (-1);
}
v = value;
return (ibuf_set(buf, pos, &v, sizeof(v)));
}
int
ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
{
uint32_t v;
if (value > UINT32_MAX) {
errno = EINVAL;
return (-1);
}
v = value;
return (ibuf_set(buf, pos, &v, sizeof(v)));
}
int
ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
{
return (ibuf_set(buf, pos, &value, sizeof(value)));
}
void *
ibuf_data(struct ibuf *buf)
ibuf_data(const struct ibuf *buf)
{
return (buf->buf);
return (buf->buf + buf->rpos);
}
size_t
ibuf_size(struct ibuf *buf)
ibuf_size(const struct ibuf *buf)
{
return (buf->wpos);
return (buf->wpos - buf->rpos);
}
size_t
ibuf_left(struct ibuf *buf)
ibuf_left(const struct ibuf *buf)
{
if (buf->max == 0)
return (0);
return (buf->max - buf->wpos);
}
int
ibuf_truncate(struct ibuf *buf, size_t len)
{
if (ibuf_size(buf) >= len) {
buf->wpos = buf->rpos + len;
return (0);
}
if (buf->max == 0) {
/* only allow to truncate down */
errno = ERANGE;
return (-1);
}
return ibuf_add_zero(buf, len - ibuf_size(buf));
}
void
ibuf_rewind(struct ibuf *buf)
{
buf->rpos = 0;
}
void
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
{
ibuf_enqueue(msgbuf, buf);
}
void
ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
{
memset(buf, 0, sizeof(*buf));
buf->buf = data;
buf->size = buf->wpos = len;
buf->fd = -1;
}
void
ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
{
ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
}
int
ibuf_get(struct ibuf *buf, void *data, size_t len)
{
if (ibuf_size(buf) < len) {
errno = EBADMSG;
return (-1);
}
memcpy(data, ibuf_data(buf), len);
buf->rpos += len;
return (0);
}
int
ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
{
if (ibuf_size(buf) < len) {
errno = EBADMSG;
return (-1);
}
ibuf_from_buffer(new, ibuf_data(buf), len);
buf->rpos += len;
return (0);
}
int
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
{
return ibuf_get(buf, value, sizeof(*value));
}
int
ibuf_get_n16(struct ibuf *buf, uint16_t *value)
{
int rv;
rv = ibuf_get(buf, value, sizeof(*value));
*value = be16toh(*value);
return (rv);
}
int
ibuf_get_n32(struct ibuf *buf, uint32_t *value)
{
int rv;
rv = ibuf_get(buf, value, sizeof(*value));
*value = be32toh(*value);
return (rv);
}
int
ibuf_get_n64(struct ibuf *buf, uint64_t *value)
{
int rv;
rv = ibuf_get(buf, value, sizeof(*value));
*value = be64toh(*value);
return (rv);
}
int
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
{
return ibuf_get(buf, value, sizeof(*value));
}
int
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
{
return ibuf_get(buf, value, sizeof(*value));
}
int
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
{
return ibuf_get(buf, value, sizeof(*value));
}
int
ibuf_skip(struct ibuf *buf, size_t len)
{
if (ibuf_size(buf) < len) {
errno = EBADMSG;
return (-1);
}
buf->rpos += len;
return (0);
}
void
ibuf_free(struct ibuf *buf)
{
if (buf == NULL)
return;
#ifdef NOTYET
if (buf->max == 0) /* if buf lives on the stack */
abort(); /* abort before causing more harm */
if (buf->fd != -1)
close(buf->fd);
#endif
freezero(buf->buf, buf->size);
free(buf);
}
@ -314,15 +518,15 @@ ibuf_fd_get(struct ibuf *buf)
int fd;
fd = buf->fd;
#ifdef NOTYET
buf->fd = -1;
#endif
return (fd);
}
void
ibuf_fd_set(struct ibuf *buf, int fd)
{
if (buf->max == 0) /* if buf lives on the stack */
abort(); /* abort before causing more harm */
if (buf->fd != -1)
close(buf->fd);
buf->fd = fd;
@ -340,8 +544,8 @@ ibuf_write(struct msgbuf *msgbuf)
TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
if (i >= IOV_MAX)
break;
iov[i].iov_base = buf->buf + buf->rpos;
iov[i].iov_len = buf->wpos - buf->rpos;
iov[i].iov_base = ibuf_data(buf);
iov[i].iov_len = ibuf_size(buf);
i++;
}
@ -380,8 +584,8 @@ msgbuf_drain(struct msgbuf *msgbuf, size_t n)
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
buf = next) {
next = TAILQ_NEXT(buf, entry);
if (n >= buf->wpos - buf->rpos) {
n -= buf->wpos - buf->rpos;
if (n >= ibuf_size(buf)) {
n -= ibuf_size(buf);
ibuf_dequeue(msgbuf, buf);
} else {
buf->rpos += n;
@ -421,8 +625,8 @@ msgbuf_write(struct msgbuf *msgbuf)
break;
if (i > 0 && buf->fd != -1)
break;
iov[i].iov_base = buf->buf + buf->rpos;
iov[i].iov_len = buf->wpos - buf->rpos;
iov[i].iov_base = ibuf_data(buf);
iov[i].iov_len = ibuf_size(buf);
i++;
if (buf->fd != -1)
buf0 = buf;
@ -469,9 +673,17 @@ again:
return (1);
}
uint32_t
msgbuf_queuelen(struct msgbuf *msgbuf)
{
return (msgbuf->queued);
}
static void
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
{
if (buf->max == 0) /* if buf lives on the stack */
abort(); /* abort before causing more harm */
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
msgbuf->queued++;
}
@ -480,12 +692,6 @@ static void
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
{
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
if (buf->fd != -1) {
close(buf->fd);
buf->fd = -1;
}
msgbuf->queued--;
ibuf_free(buf);
}

View File

@ -1,6 +1,7 @@
/* $OpenBSD: imsg.c,v 1.19 2023/06/19 17:19:50 claudio Exp $ */
/* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */
/*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -29,23 +30,28 @@
#include "imsg.h"
struct imsg_fd {
TAILQ_ENTRY(imsg_fd) entry;
int fd;
};
int imsg_fd_overhead = 0;
static int imsg_get_fd(struct imsgbuf *);
static int imsg_dequeue_fd(struct imsgbuf *);
void
imsg_init(struct imsgbuf *ibuf, int fd)
imsg_init(struct imsgbuf *imsgbuf, int fd)
{
msgbuf_init(&ibuf->w);
memset(&ibuf->r, 0, sizeof(ibuf->r));
ibuf->fd = fd;
ibuf->w.fd = fd;
ibuf->pid = getpid();
TAILQ_INIT(&ibuf->fds);
msgbuf_init(&imsgbuf->w);
memset(&imsgbuf->r, 0, sizeof(imsgbuf->r));
imsgbuf->fd = fd;
imsgbuf->w.fd = fd;
imsgbuf->pid = getpid();
TAILQ_INIT(&imsgbuf->fds);
}
ssize_t
imsg_read(struct imsgbuf *ibuf)
imsg_read(struct imsgbuf *imsgbuf)
{
struct msghdr msg;
struct cmsghdr *cmsg;
@ -61,8 +67,8 @@ imsg_read(struct imsgbuf *ibuf)
memset(&msg, 0, sizeof(msg));
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos;
iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgbuf.buf;
@ -80,13 +86,13 @@ again:
return (-1);
}
if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) {
if (errno == EINTR)
goto again;
goto fail;
}
ibuf->r.wpos += n;
imsgbuf->r.wpos += n;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@ -106,7 +112,7 @@ again:
fd = ((int *)CMSG_DATA(cmsg))[i];
if (ifd != NULL) {
ifd->fd = fd;
TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd,
entry);
ifd = NULL;
} else
@ -122,77 +128,145 @@ fail:
}
ssize_t
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
{
struct imsg m;
size_t av, left, datalen;
av = ibuf->r.wpos;
av = imsgbuf->r.wpos;
if (IMSG_HEADER_SIZE > av)
return (0);
memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
if (imsg->hdr.len < IMSG_HEADER_SIZE ||
imsg->hdr.len > MAX_IMSGSIZE) {
memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr));
if (m.hdr.len < IMSG_HEADER_SIZE ||
m.hdr.len > MAX_IMSGSIZE) {
errno = ERANGE;
return (-1);
}
if (imsg->hdr.len > av)
if (m.hdr.len > av)
return (0);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
if (datalen == 0)
imsg->data = NULL;
else if ((imsg->data = malloc(datalen)) == NULL)
return (-1);
if (imsg->hdr.flags & IMSGF_HASFD)
imsg->fd = imsg_get_fd(ibuf);
else
imsg->fd = -1;
m.fd = -1;
m.buf = NULL;
m.data = NULL;
if (datalen != 0)
memcpy(imsg->data, ibuf->r.rptr, datalen);
datalen = m.hdr.len - IMSG_HEADER_SIZE;
imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE;
if (datalen != 0) {
if ((m.buf = ibuf_open(datalen)) == NULL)
return (-1);
if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) {
/* this should never fail */
ibuf_free(m.buf);
return (-1);
}
m.data = ibuf_data(m.buf);
}
if (imsg->hdr.len < av) {
left = av - imsg->hdr.len;
memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
ibuf->r.wpos = left;
if (m.hdr.flags & IMSGF_HASFD)
m.fd = imsg_dequeue_fd(imsgbuf);
if (m.hdr.len < av) {
left = av - m.hdr.len;
memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left);
imsgbuf->r.wpos = left;
} else
ibuf->r.wpos = 0;
imsgbuf->r.wpos = 0;
*imsg = m;
return (datalen + IMSG_HEADER_SIZE);
}
int
imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
int fd, const void *data, uint16_t datalen)
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
{
if (imsg->buf == NULL) {
errno = EBADMSG;
return (-1);
}
return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf);
}
int
imsg_get_data(struct imsg *imsg, void *data, size_t len)
{
if (len == 0) {
errno = EINVAL;
return (-1);
}
if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) {
errno = EBADMSG;
return (-1);
}
return ibuf_get(imsg->buf, data, len);
}
int
imsg_get_fd(struct imsg *imsg)
{
int fd = imsg->fd;
imsg->fd = -1;
return fd;
}
uint32_t
imsg_get_id(struct imsg *imsg)
{
return (imsg->hdr.peerid);
}
size_t
imsg_get_len(struct imsg *imsg)
{
if (imsg->buf == NULL)
return 0;
return ibuf_size(imsg->buf);
}
pid_t
imsg_get_pid(struct imsg *imsg)
{
return (imsg->hdr.pid);
}
uint32_t
imsg_get_type(struct imsg *imsg)
{
return (imsg->hdr.type);
}
int
imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
int fd, const void *data, size_t datalen)
{
struct ibuf *wbuf;
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
return (-1);
if (imsg_add(wbuf, data, datalen) == -1)
return (-1);
ibuf_fd_set(wbuf, fd);
imsg_close(ibuf, wbuf);
imsg_close(imsgbuf, wbuf);
return (1);
}
int
imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
int fd, const struct iovec *iov, int iovcnt)
{
struct ibuf *wbuf;
int i, datalen = 0;
int i;
size_t datalen = 0;
for (i = 0; i < iovcnt; i++)
datalen += iov[i].iov_len;
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
return (-1);
for (i = 0; i < iovcnt; i++)
@ -200,16 +274,20 @@ imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
return (-1);
ibuf_fd_set(wbuf, fd);
imsg_close(ibuf, wbuf);
imsg_close(imsgbuf, wbuf);
return (1);
}
/*
* Enqueue imsg with payload from ibuf buf. fd passing is not possible
* with this function.
*/
int
imsg_compose_ibuf(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
pid_t pid, struct ibuf *buf)
{
struct ibuf *wbuf = NULL;
struct ibuf *hdrbuf = NULL;
struct imsg_hdr hdr;
int save_errno;
@ -221,30 +299,64 @@ imsg_compose_ibuf(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
hdr.type = type;
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
hdr.flags = 0;
hdr.peerid = peerid;
hdr.peerid = id;
if ((hdr.pid = pid) == 0)
hdr.pid = ibuf->pid;
hdr.pid = imsgbuf->pid;
if ((wbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
goto fail;
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
goto fail;
ibuf_close(&ibuf->w, wbuf);
ibuf_close(&ibuf->w, buf);
ibuf_close(&imsgbuf->w, hdrbuf);
ibuf_close(&imsgbuf->w, buf);
return (1);
fail:
save_errno = errno;
ibuf_free(buf);
ibuf_free(wbuf);
ibuf_free(hdrbuf);
errno = save_errno;
return (-1);
}
/*
* Forward imsg to another channel. Any attached fd is closed.
*/
int
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
{
struct ibuf *wbuf;
size_t len = 0;
if (msg->fd != -1) {
close(msg->fd);
msg->fd = -1;
}
if (msg->buf != NULL) {
ibuf_rewind(msg->buf);
len = ibuf_size(msg->buf);
}
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
msg->hdr.pid, len)) == NULL)
return (-1);
if (msg->buf != NULL) {
if (ibuf_add_buf(wbuf, msg->buf) == -1) {
ibuf_free(wbuf);
return (-1);
}
}
imsg_close(imsgbuf, wbuf);
return (1);
}
struct ibuf *
imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
uint16_t datalen)
imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
size_t datalen)
{
struct ibuf *wbuf;
struct imsg_hdr hdr;
@ -257,9 +369,9 @@ imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
hdr.type = type;
hdr.flags = 0;
hdr.peerid = peerid;
hdr.peerid = id;
if ((hdr.pid = pid) == 0)
hdr.pid = ibuf->pid;
hdr.pid = imsgbuf->pid;
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
return (NULL);
}
@ -270,7 +382,7 @@ imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
}
int
imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
imsg_add(struct ibuf *msg, const void *data, size_t datalen)
{
if (datalen)
if (ibuf_add(msg, data, datalen) == -1) {
@ -281,7 +393,7 @@ imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
}
void
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
{
struct imsg_hdr *hdr;
@ -292,46 +404,46 @@ imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
hdr->flags |= IMSGF_HASFD;
hdr->len = ibuf_size(msg);
ibuf_close(&ibuf->w, msg);
ibuf_close(&imsgbuf->w, msg);
}
void
imsg_free(struct imsg *imsg)
{
freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
ibuf_free(imsg->buf);
}
static int
imsg_get_fd(struct imsgbuf *ibuf)
imsg_dequeue_fd(struct imsgbuf *imsgbuf)
{
int fd;
struct imsg_fd *ifd;
if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL)
return (-1);
fd = ifd->fd;
TAILQ_REMOVE(&ibuf->fds, ifd, entry);
TAILQ_REMOVE(&imsgbuf->fds, ifd, entry);
free(ifd);
return (fd);
}
int
imsg_flush(struct imsgbuf *ibuf)
imsg_flush(struct imsgbuf *imsgbuf)
{
while (ibuf->w.queued)
if (msgbuf_write(&ibuf->w) <= 0)
while (imsgbuf->w.queued)
if (msgbuf_write(&imsgbuf->w) <= 0)
return (-1);
return (0);
}
void
imsg_clear(struct imsgbuf *ibuf)
imsg_clear(struct imsgbuf *imsgbuf)
{
int fd;
msgbuf_clear(&ibuf->w);
while ((fd = imsg_get_fd(ibuf)) != -1)
msgbuf_clear(&imsgbuf->w);
while ((fd = imsg_dequeue_fd(imsgbuf)) != -1)
close(fd);
}

View File

@ -1,6 +1,7 @@
/* $OpenBSD: imsg.h,v 1.7 2023/06/19 17:19:50 claudio Exp $ */
/* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */
/*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
* Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -21,7 +22,7 @@
#ifndef _IMSG_H_
#define _IMSG_H_
#include <stdint.h>
#include <sys/types.h>
#define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
@ -49,11 +50,7 @@ struct ibuf_read {
size_t wpos;
};
struct imsg_fd {
TAILQ_ENTRY(imsg_fd) entry;
int fd;
};
struct imsg_fd;
struct imsgbuf {
TAILQ_HEAD(, imsg_fd) fds;
struct ibuf_read r;
@ -76,6 +73,7 @@ struct imsg {
struct imsg_hdr hdr;
int fd;
void *data;
struct ibuf *buf;
};
struct iovec;
@ -85,11 +83,15 @@ struct ibuf *ibuf_open(size_t);
struct ibuf *ibuf_dynamic(size_t, size_t);
int ibuf_add(struct ibuf *, const void *, size_t);
int ibuf_add_buf(struct ibuf *, const struct ibuf *);
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_add_zero(struct ibuf *, size_t);
int ibuf_add_n8(struct ibuf *, uint64_t);
int ibuf_add_n16(struct ibuf *, uint64_t);
int ibuf_add_n32(struct ibuf *, uint64_t);
int ibuf_add_n64(struct ibuf *, uint64_t);
int ibuf_add_h16(struct ibuf *, uint64_t);
int ibuf_add_h32(struct ibuf *, uint64_t);
int ibuf_add_h64(struct ibuf *, uint64_t);
void *ibuf_reserve(struct ibuf *, size_t);
void *ibuf_seek(struct ibuf *, size_t, size_t);
int ibuf_set(struct ibuf *, size_t, const void *, size_t);
@ -97,10 +99,27 @@ int ibuf_set_n8(struct ibuf *, size_t, uint64_t);
int ibuf_set_n16(struct ibuf *, size_t, uint64_t);
int ibuf_set_n32(struct ibuf *, size_t, uint64_t);
int ibuf_set_n64(struct ibuf *, size_t, uint64_t);
void *ibuf_data(struct ibuf *);
size_t ibuf_size(struct ibuf *);
size_t ibuf_left(struct ibuf *);
int ibuf_set_h16(struct ibuf *, size_t, uint64_t);
int ibuf_set_h32(struct ibuf *, size_t, uint64_t);
int ibuf_set_h64(struct ibuf *, size_t, uint64_t);
void *ibuf_data(const struct ibuf *);
size_t ibuf_size(const struct ibuf *);
size_t ibuf_left(const struct ibuf *);
int ibuf_truncate(struct ibuf *, size_t);
void ibuf_rewind(struct ibuf *);
void ibuf_close(struct msgbuf *, struct ibuf *);
void ibuf_from_buffer(struct ibuf *, void *, size_t);
void ibuf_from_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_get(struct ibuf *, void *, size_t);
int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *);
int ibuf_get_n8(struct ibuf *, uint8_t *);
int ibuf_get_n16(struct ibuf *, uint16_t *);
int ibuf_get_n32(struct ibuf *, uint32_t *);
int ibuf_get_n64(struct ibuf *, uint64_t *);
int ibuf_get_h16(struct ibuf *, uint16_t *);
int ibuf_get_h32(struct ibuf *, uint32_t *);
int ibuf_get_h64(struct ibuf *, uint64_t *);
int ibuf_skip(struct ibuf *, size_t);
void ibuf_free(struct ibuf *);
int ibuf_fd_avail(struct ibuf *);
int ibuf_fd_get(struct ibuf *);
@ -108,20 +127,29 @@ void ibuf_fd_set(struct ibuf *, int);
int ibuf_write(struct msgbuf *);
void msgbuf_init(struct msgbuf *);
void msgbuf_clear(struct msgbuf *);
uint32_t msgbuf_queuelen(struct msgbuf *);
int msgbuf_write(struct msgbuf *);
/* imsg.c */
void imsg_init(struct imsgbuf *, int);
ssize_t imsg_read(struct imsgbuf *);
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
int imsg_get_ibuf(struct imsg *, struct ibuf *);
int imsg_get_data(struct imsg *, void *, size_t);
int imsg_get_fd(struct imsg *);
uint32_t imsg_get_id(struct imsg *);
size_t imsg_get_len(struct imsg *);
pid_t imsg_get_pid(struct imsg *);
uint32_t imsg_get_type(struct imsg *);
int imsg_forward(struct imsgbuf *, struct imsg *);
int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const void *, uint16_t);
const void *, size_t);
int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const struct iovec *, int);
int imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t,
struct ibuf *);
struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, uint16_t);
int imsg_add(struct ibuf *, const void *, uint16_t);
struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t);
int imsg_add(struct ibuf *, const void *, size_t);
void imsg_close(struct imsgbuf *, struct ibuf *);
void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);

View File

@ -13,6 +13,7 @@ DISTFILES = Makefile \
tls_ocsp.c \
tls_peer.c \
tls_server.c \
tls_signer.c \
tls_util.c \
tls_verify.c

View File

@ -26,38 +26,38 @@
#define GENTIME_LENGTH 15
#define UTCTIME_LENGTH 13
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
#ifndef HAVE_ASN1_TIME_TM_CMP
int
ASN1_time_tm_cmp(struct tm *tm1, struct tm *tm2)
{
if (tm1->tm_year < tm2->tm_year)
return (-1);
if (tm1->tm_year > tm2->tm_year)
return (1);
if (tm1->tm_mon < tm2->tm_mon)
return (-1);
if (tm1->tm_mon > tm2->tm_mon)
return (1);
if (tm1->tm_mday < tm2->tm_mday)
return (-1);
if (tm1->tm_mday > tm2->tm_mday)
return (1);
if (tm1->tm_hour < tm2->tm_hour)
return (-1);
if (tm1->tm_hour > tm2->tm_hour)
return (1);
if (tm1->tm_min < tm2->tm_min)
return (-1);
if (tm1->tm_min > tm2->tm_min)
return (1);
if (tm1->tm_sec < tm2->tm_sec)
return (-1);
if (tm1->tm_sec > tm2->tm_sec)
return (1);
return 0;
if (tm1->tm_year < tm2->tm_year)
return (-1);
if (tm1->tm_year > tm2->tm_year)
return (1);
if (tm1->tm_mon < tm2->tm_mon)
return (-1);
if (tm1->tm_mon > tm2->tm_mon)
return (1);
if (tm1->tm_mday < tm2->tm_mday)
return (-1);
if (tm1->tm_mday > tm2->tm_mday)
return (1);
if (tm1->tm_hour < tm2->tm_hour)
return (-1);
if (tm1->tm_hour > tm2->tm_hour)
return (1);
if (tm1->tm_min < tm2->tm_min)
return (-1);
if (tm1->tm_min > tm2->tm_min)
return (1);
if (tm1->tm_sec < tm2->tm_sec)
return (-1);
if (tm1->tm_sec > tm2->tm_sec)
return (1);
return 0;
}
#endif
@ -66,112 +66,15 @@ int
ASN1_time_tm_clamp_notafter(struct tm *tm)
{
#ifdef SMALL_TIME_T
struct tm broken_os_epoch_tm;
time_t broken_os_epoch_time = INT_MAX;
struct tm broken_os_epoch_tm;
time_t broken_os_epoch_time = INT_MAX;
if (gmtime_r(&broken_os_epoch_time, &broken_os_epoch_tm) == NULL)
return 0;
if (gmtime_r(&broken_os_epoch_time, &broken_os_epoch_tm) == NULL)
return 0;
if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1)
memcpy(tm, &broken_os_epoch_tm, sizeof(*tm));
if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1)
memcpy(tm, &broken_os_epoch_tm, sizeof(*tm));
#endif
return 1;
}
#endif
/*
* Parse an RFC 5280 format ASN.1 time string.
*
* mode must be:
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
*
* Returns:
* -1 if the string was invalid.
* V_ASN1_UTCTIME if the string validated as a UTC time string.
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
*
* Fills in *tm with the corresponding time if tm is non NULL.
*/
#ifndef HAVE_ASN1_TIME_PARSE
#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
int
ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode)
{
size_t i;
int type = 0;
struct tm ltm;
struct tm *lt;
const char *p;
if (bytes == NULL)
return (-1);
/* Constrain to valid lengths. */
if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH)
return (-1);
lt = tm;
if (lt == NULL) {
memset(&ltm, 0, sizeof(ltm));
lt = &ltm;
}
/* Timezone is required and must be GMT (Zulu). */
if (bytes[len - 1] != 'Z')
return (-1);
/* Make sure everything else is digits. */
for (i = 0; i < len - 1; i++) {
if (isdigit((unsigned char)bytes[i]))
continue;
return (-1);
}
/*
* Validate and convert the time
*/
p = bytes;
switch (len) {
case GENTIME_LENGTH:
if (mode == V_ASN1_UTCTIME)
return (-1);
lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */
type = V_ASN1_GENERALIZEDTIME;
/* FALLTHROUGH */
case UTCTIME_LENGTH:
if (type == 0) {
if (mode == V_ASN1_GENERALIZEDTIME)
return (-1);
type = V_ASN1_UTCTIME;
}
lt->tm_year += ATOI2(p); /* yy */
if (type == V_ASN1_UTCTIME) {
if (lt->tm_year < 50)
lt->tm_year += 100;
}
lt->tm_mon = ATOI2(p) - 1; /* mm */
if (lt->tm_mon < 0 || lt->tm_mon > 11)
return (-1);
lt->tm_mday = ATOI2(p); /* dd */
if (lt->tm_mday < 1 || lt->tm_mday > 31)
return (-1);
lt->tm_hour = ATOI2(p); /* HH */
if (lt->tm_hour < 0 || lt->tm_hour > 23)
return (-1);
lt->tm_min = ATOI2(p); /* MM */
if (lt->tm_min < 0 || lt->tm_min > 59)
return (-1);
lt->tm_sec = ATOI2(p); /* SS */
/* Leap second 60 is not accepted. Reconsider later? */
if (lt->tm_sec < 0 || lt->tm_sec > 59)
return (-1);
break;
default:
return (-1);
}
return (type);
return 1;
}
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls.c,v 1.97 2023/06/18 11:43:03 op Exp $ */
/* $OpenBSD: tls.c,v 1.98 2023/07/02 06:37:27 beck Exp $ */
/*
* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
*
@ -384,6 +384,8 @@ tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pke
static int
tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey)
{
RSA_METHOD *rsa_method;
EC_KEY_METHOD *ecdsa_method;
RSA *rsa = NULL;
EC_KEY *eckey = NULL;
int ret = -1;
@ -400,19 +402,45 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
switch (EVP_PKEY_id(pkey)) {
case EVP_PKEY_RSA:
if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0 ||
EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0) {
tls_set_errorx(ctx, "RSA key setup failure");
goto err;
}
if (ctx->config->sign_cb != NULL) {
rsa_method = tls_signer_rsa_method();
if (rsa_method == NULL ||
RSA_set_ex_data(rsa, 1, ctx->config) == 0 ||
RSA_set_method(rsa, rsa_method) == 0) {
tls_set_errorx(ctx, "failed to setup RSA key");
goto err;
}
}
/* Reset the key to work around caching in OpenSSL 3. */
if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
tls_set_errorx(ctx, "failed to set RSA key");
goto err;
}
break;
case EVP_PKEY_EC:
if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0 ||
EVP_PKEY_set1_EC_KEY(pkey, eckey) == 0) {
EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
tls_set_errorx(ctx, "EC key setup failure");
goto err;
}
if (ctx->config->sign_cb != NULL) {
ecdsa_method = tls_signer_ecdsa_method();
if (ecdsa_method == NULL ||
EC_KEY_set_ex_data(eckey, 1, ctx->config) == 0 ||
EC_KEY_set_method(eckey, ecdsa_method) == 0) {
tls_set_errorx(ctx, "failed to setup EC key");
goto err;
}
}
/* Reset the key to work around caching in OpenSSL 3. */
if (EVP_PKEY_set1_EC_KEY(pkey, eckey) == 0) {
tls_set_errorx(ctx, "failed to set EC key");
goto err;
}
break;
default:
tls_set_errorx(ctx, "incorrect key type");
@ -488,16 +516,12 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3);
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_3) == 0)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls.h,v 1.62 2022/03/24 15:56:34 tb Exp $ */
/* $OpenBSD: tls.h,v 1.63 2023/07/02 06:37:27 beck Exp $ */
/*
* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
*
@ -29,14 +29,18 @@ extern "C" {
#define TLS_API 20200120
#define TLS_PROTOCOL_TLSv1_0 (1 << 1)
#define TLS_PROTOCOL_TLSv1_1 (1 << 2)
/*
* Deprecated versions of TLS. Using these effectively selects
* the minimum supported version.
*/
#define TLS_PROTOCOL_TLSv1_0 (1 << 3)
#define TLS_PROTOCOL_TLSv1_1 (1 << 3)
/* Supported versions of TLS */
#define TLS_PROTOCOL_TLSv1_2 (1 << 3)
#define TLS_PROTOCOL_TLSv1_3 (1 << 4)
#define TLS_PROTOCOL_TLSv1 \
(TLS_PROTOCOL_TLSv1_0|TLS_PROTOCOL_TLSv1_1|\
TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3)
(TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3)
#define TLS_PROTOCOLS_ALL TLS_PROTOCOL_TLSv1
#define TLS_PROTOCOLS_DEFAULT (TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls_config.c,v 1.66 2023/05/14 07:26:25 op Exp $ */
/* $OpenBSD: tls_config.c,v 1.67 2023/07/02 06:37:27 beck Exp $ */
/*
* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
*
@ -247,9 +247,9 @@ tls_config_parse_protocols(uint32_t *protocols, const char *protostr)
if (strcasecmp(p, "tlsv1") == 0)
proto = TLS_PROTOCOL_TLSv1;
else if (strcasecmp(p, "tlsv1.0") == 0)
proto = TLS_PROTOCOL_TLSv1_0;
proto = TLS_PROTOCOL_TLSv1_2;
else if (strcasecmp(p, "tlsv1.1") == 0)
proto = TLS_PROTOCOL_TLSv1_1;
proto = TLS_PROTOCOL_TLSv1_2;
else if (strcasecmp(p, "tlsv1.2") == 0)
proto = TLS_PROTOCOL_TLSv1_2;
else if (strcasecmp(p, "tlsv1.3") == 0)
@ -734,6 +734,17 @@ tls_config_set_session_fd(struct tls_config *config, int session_fd)
return (0);
}
int
tls_config_set_sign_cb(struct tls_config *config, tls_sign_cb cb, void *cb_arg)
{
config->use_fake_private_key = 1;
config->skip_private_key_check = 1;
config->sign_cb = cb;
config->sign_cb_arg = cb_arg;
return (0);
}
int
tls_config_set_verify_depth(struct tls_config *config, int verify_depth)
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls_conninfo.c,v 1.23 2023/05/14 07:26:25 op Exp $ */
/* $OpenBSD: tls_conninfo.c,v 1.24 2023/11/13 10:51:49 tb Exp $ */
/*
* Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
* Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@ -119,9 +119,9 @@ tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
goto err;
if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL)
goto err;
if (ASN1_time_parse(before->data, before->length, &before_tm, 0) == -1)
if (!ASN1_TIME_to_tm(before, &before_tm))
goto err;
if (ASN1_time_parse(after->data, after->length, &after_tm, 0) == -1)
if (!ASN1_TIME_to_tm(after, &after_tm))
goto err;
if (!ASN1_time_tm_clamp_notafter(&after_tm))
goto err;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls_internal.h,v 1.82 2023/06/18 11:43:03 op Exp $ */
/* $OpenBSD: tls_internal.h,v 1.83 2023/06/27 18:19:59 tb Exp $ */
/*
* Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@ -70,6 +70,10 @@ struct tls_ticket_key {
time_t time;
};
typedef int (*tls_sign_cb)(void *_cb_arg, const char *_pubkey_hash,
const uint8_t *_input, size_t _input_len, int _padding_type,
uint8_t **_out_signature, size_t *_out_signature_len);
struct tls_config {
struct tls_error error;
@ -103,6 +107,8 @@ struct tls_config {
int verify_time;
int skip_private_key_check;
int use_fake_private_key;
tls_sign_cb sign_cb;
void *sign_cb_arg;
};
struct tls_conninfo {
@ -282,13 +288,30 @@ int tls_cert_pubkey_hash(X509 *_cert, char **_hash);
int tls_password_cb(char *_buf, int _size, int _rwflag, void *_u);
RSA_METHOD *tls_signer_rsa_method(void);
EC_KEY_METHOD *tls_signer_ecdsa_method(void);
#define TLS_PADDING_NONE 0
#define TLS_PADDING_RSA_PKCS1 1
int tls_config_set_sign_cb(struct tls_config *_config, tls_sign_cb _cb,
void *_cb_arg);
struct tls_signer* tls_signer_new(void);
void tls_signer_free(struct tls_signer * _signer);
const char *tls_signer_error(struct tls_signer * _signer);
int tls_signer_add_keypair_file(struct tls_signer *_signer,
const char *_cert_file, const char *_key_file);
int tls_signer_add_keypair_mem(struct tls_signer *_signer, const uint8_t *_cert,
size_t _cert_len, const uint8_t *_key, size_t _key_len);
int tls_signer_sign(struct tls_signer *_signer, const char *_pubkey_hash,
const uint8_t *_input, size_t _input_len, int _padding_type,
uint8_t **_out_signature, size_t *_out_signature_len);
/* XXX this function is not fully hidden so relayd can use it */
void tls_config_skip_private_key_check(struct tls_config *config);
void tls_config_use_fake_private_key(struct tls_config *config);
/* XXX prototypes brought for OpenSMTPD libtls wrapper to OpenSSL */
int ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode);
#ifndef HAVE_SSL_CTX_USE_CERTIFICATE_CHAIN_MEM
int SSL_CTX_use_certificate_chain_mem(SSL_CTX *, void *, int);
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls_ocsp.c,v 1.23 2023/05/14 07:26:25 op Exp $ */
/* $OpenBSD: tls_ocsp.c,v 1.24 2023/11/13 10:56:19 tb Exp $ */
/*
* Copyright (c) 2015 Marko Kreen <markokr@gmail.com>
* Copyright (c) 2016 Bob Beck <beck@openbsd.org>
@ -66,8 +66,9 @@ tls_ocsp_asn1_parse_time(struct tls *ctx, ASN1_GENERALIZEDTIME *gt, time_t *gt_t
if (gt == NULL)
return -1;
/* RFC 6960 specifies that all times in OCSP must be GENERALIZEDTIME */
if (ASN1_time_parse(gt->data, gt->length, &tm,
V_ASN1_GENERALIZEDTIME) == -1)
if (!ASN1_GENERALIZEDTIME_check(gt))
return -1;
if (!ASN1_TIME_to_tm(gt, &tm))
return -1;
if ((*gt_time = timegm(&tm)) == -1)
return -1;

443
compat/libtls/tls_signer.c Normal file
View File

@ -0,0 +1,443 @@
/* $OpenBSD: tls_signer.c,v 1.9 2023/06/18 19:12:58 tb Exp $ */
/*
* Copyright (c) 2021 Eric Faurot <eric@openbsd.org>
*
* 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.
*/
#include "config.h"
#include <limits.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "tls.h"
#include "tls_internal.h"
struct tls_signer_key {
char *hash;
RSA *rsa;
EC_KEY *ecdsa;
struct tls_signer_key *next;
};
struct tls_signer {
struct tls_error error;
struct tls_signer_key *keys;
};
struct tls_signer *
tls_signer_new(void)
{
struct tls_signer *signer;
if ((signer = calloc(1, sizeof(*signer))) == NULL)
return (NULL);
return (signer);
}
void
tls_signer_free(struct tls_signer *signer)
{
struct tls_signer_key *skey;
if (signer == NULL)
return;
tls_error_clear(&signer->error);
while (signer->keys) {
skey = signer->keys;
signer->keys = skey->next;
RSA_free(skey->rsa);
EC_KEY_free(skey->ecdsa);
free(skey->hash);
free(skey);
}
free(signer);
}
const char *
tls_signer_error(struct tls_signer *signer)
{
return (signer->error.msg);
}
int
tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert,
size_t cert_len, const uint8_t *key, size_t key_len)
{
struct tls_signer_key *skey = NULL;
char *errstr = "unknown";
int ssl_err;
EVP_PKEY *pkey = NULL;
X509 *x509 = NULL;
BIO *bio = NULL;
char *hash = NULL;
/* Compute certificate hash */
if ((bio = BIO_new_mem_buf(cert, cert_len)) == NULL) {
tls_error_setx(&signer->error,
"failed to create certificate bio");
goto err;
}
if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
NULL)) == NULL) {
if ((ssl_err = ERR_peek_error()) != 0)
errstr = ERR_error_string(ssl_err, NULL);
tls_error_setx(&signer->error, "failed to load certificate: %s",
errstr);
goto err;
}
if (tls_cert_pubkey_hash(x509, &hash) == -1) {
tls_error_setx(&signer->error,
"failed to get certificate hash");
goto err;
}
X509_free(x509);
x509 = NULL;
BIO_free(bio);
bio = NULL;
/* Read private key */
if ((bio = BIO_new_mem_buf(key, key_len)) == NULL) {
tls_error_setx(&signer->error, "failed to create key bio");
goto err;
}
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
NULL)) == NULL) {
tls_error_setx(&signer->error, "failed to read private key");
goto err;
}
if ((skey = calloc(1, sizeof(*skey))) == NULL) {
tls_error_set(&signer->error, "failed to create key entry");
goto err;
}
skey->hash = hash;
if ((skey->rsa = EVP_PKEY_get1_RSA(pkey)) == NULL &&
(skey->ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
tls_error_setx(&signer->error, "unknown key type");
goto err;
}
skey->next = signer->keys;
signer->keys = skey;
EVP_PKEY_free(pkey);
BIO_free(bio);
return (0);
err:
EVP_PKEY_free(pkey);
X509_free(x509);
BIO_free(bio);
free(hash);
free(skey);
return (-1);
}
int
tls_signer_add_keypair_file(struct tls_signer *signer, const char *cert_file,
const char *key_file)
{
char *cert = NULL, *key = NULL;
size_t cert_len, key_len;
int rv = -1;
if (tls_config_load_file(&signer->error, "certificate", cert_file,
&cert, &cert_len) == -1)
goto err;
if (tls_config_load_file(&signer->error, "key", key_file, &key,
&key_len) == -1)
goto err;
rv = tls_signer_add_keypair_mem(signer, cert, cert_len, key, key_len);
err:
free(cert);
free(key);
return (rv);
}
static int
tls_sign_rsa(struct tls_signer *signer, struct tls_signer_key *skey,
const uint8_t *input, size_t input_len, int padding_type,
uint8_t **out_signature, size_t *out_signature_len)
{
int rsa_padding, rsa_size, signature_len;
char *signature = NULL;
*out_signature = NULL;
*out_signature_len = 0;
if (padding_type == TLS_PADDING_NONE) {
rsa_padding = RSA_NO_PADDING;
} else if (padding_type == TLS_PADDING_RSA_PKCS1) {
rsa_padding = RSA_PKCS1_PADDING;
} else {
tls_error_setx(&signer->error, "invalid RSA padding type (%d)",
padding_type);
return (-1);
}
if (input_len > INT_MAX) {
tls_error_setx(&signer->error, "input too large");
return (-1);
}
if ((rsa_size = RSA_size(skey->rsa)) <= 0) {
tls_error_setx(&signer->error, "invalid RSA size: %d",
rsa_size);
return (-1);
}
if ((signature = calloc(1, rsa_size)) == NULL) {
tls_error_set(&signer->error, "RSA signature");
return (-1);
}
if ((signature_len = RSA_private_encrypt((int)input_len, input,
signature, skey->rsa, rsa_padding)) <= 0) {
/* XXX - include further details from libcrypto. */
tls_error_setx(&signer->error, "RSA signing failed");
free(signature);
return (-1);
}
*out_signature = signature;
*out_signature_len = (size_t)signature_len;
return (0);
}
static int
tls_sign_ecdsa(struct tls_signer *signer, struct tls_signer_key *skey,
const uint8_t *input, size_t input_len, int padding_type,
uint8_t **out_signature, size_t *out_signature_len)
{
unsigned char *signature;
int signature_len;
*out_signature = NULL;
*out_signature_len = 0;
if (padding_type != TLS_PADDING_NONE) {
tls_error_setx(&signer->error, "invalid ECDSA padding");
return (-1);
}
if (input_len > INT_MAX) {
tls_error_setx(&signer->error, "digest too large");
return (-1);
}
if ((signature_len = ECDSA_size(skey->ecdsa)) <= 0) {
tls_error_setx(&signer->error, "invalid ECDSA size: %d",
signature_len);
return (-1);
}
if ((signature = calloc(1, signature_len)) == NULL) {
tls_error_set(&signer->error, "ECDSA signature");
return (-1);
}
if (!ECDSA_sign(0, input, input_len, signature, &signature_len,
skey->ecdsa)) {
/* XXX - include further details from libcrypto. */
tls_error_setx(&signer->error, "ECDSA signing failed");
free(signature);
return (-1);
}
*out_signature = signature;
*out_signature_len = signature_len;
return (0);
}
int
tls_signer_sign(struct tls_signer *signer, const char *pubkey_hash,
const uint8_t *input, size_t input_len, int padding_type,
uint8_t **out_signature, size_t *out_signature_len)
{
struct tls_signer_key *skey;
*out_signature = NULL;
*out_signature_len = 0;
for (skey = signer->keys; skey; skey = skey->next)
if (!strcmp(pubkey_hash, skey->hash))
break;
if (skey == NULL) {
tls_error_setx(&signer->error, "key not found");
return (-1);
}
if (skey->rsa != NULL)
return tls_sign_rsa(signer, skey, input, input_len,
padding_type, out_signature, out_signature_len);
if (skey->ecdsa != NULL)
return tls_sign_ecdsa(signer, skey, input, input_len,
padding_type, out_signature, out_signature_len);
tls_error_setx(&signer->error, "unknown key type");
return (-1);
}
static int
tls_rsa_priv_enc(int from_len, const unsigned char *from, unsigned char *to,
RSA *rsa, int rsa_padding)
{
struct tls_config *config;
uint8_t *signature = NULL;
size_t signature_len = 0;
const char *pubkey_hash;
int padding_type;
/*
* This function is called via RSA_private_encrypt() and has to conform
* to its calling convention/signature. The caller is required to
* provide a 'to' buffer of at least RSA_size() bytes.
*/
pubkey_hash = RSA_get_ex_data(rsa, 0);
config = RSA_get_ex_data(rsa, 1);
if (pubkey_hash == NULL || config == NULL)
goto err;
if (rsa_padding == RSA_NO_PADDING) {
padding_type = TLS_PADDING_NONE;
} else if (rsa_padding == RSA_PKCS1_PADDING) {
padding_type = TLS_PADDING_RSA_PKCS1;
} else {
goto err;
}
if (from_len < 0)
goto err;
if (config->sign_cb(config->sign_cb_arg, pubkey_hash, from, from_len,
padding_type, &signature, &signature_len) == -1)
goto err;
if (signature_len > INT_MAX || (int)signature_len > RSA_size(rsa))
goto err;
memcpy(to, signature, signature_len);
free(signature);
return ((int)signature_len);
err:
free(signature);
return (-1);
}
RSA_METHOD *
tls_signer_rsa_method(void)
{
static RSA_METHOD *rsa_method = NULL;
if (rsa_method != NULL)
goto out;
rsa_method = RSA_meth_new("libtls RSA method", 0);
if (rsa_method == NULL)
goto out;
RSA_meth_set_priv_enc(rsa_method, tls_rsa_priv_enc);
out:
return (rsa_method);
}
static ECDSA_SIG *
tls_ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
const BIGNUM *rp, EC_KEY *eckey)
{
struct tls_config *config;
ECDSA_SIG *ecdsa_sig = NULL;
uint8_t *signature = NULL;
size_t signature_len = 0;
const unsigned char *p;
const char *pubkey_hash;
/*
* This function is called via ECDSA_do_sign_ex() and has to conform
* to its calling convention/signature.
*/
pubkey_hash = EC_KEY_get_ex_data(eckey, 0);
config = EC_KEY_get_ex_data(eckey, 1);
if (pubkey_hash == NULL || config == NULL)
goto err;
if (dgst_len < 0)
goto err;
if (config->sign_cb(config->sign_cb_arg, pubkey_hash, dgst, dgst_len,
TLS_PADDING_NONE, &signature, &signature_len) == -1)
goto err;
p = signature;
if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &p, signature_len)) == NULL)
goto err;
free(signature);
return (ecdsa_sig);
err:
free(signature);
return (NULL);
}
EC_KEY_METHOD *
tls_signer_ecdsa_method(void)
{
static EC_KEY_METHOD *ecdsa_method = NULL;
const EC_KEY_METHOD *default_method;
int (*sign)(int type, const unsigned char *dgst, int dlen,
unsigned char *sig, unsigned int *siglen,
const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey);
int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in,
BIGNUM **kinvp, BIGNUM **rp);
if (ecdsa_method != NULL)
goto out;
default_method = EC_KEY_get_default_method();
ecdsa_method = EC_KEY_METHOD_new(default_method);
if (ecdsa_method == NULL)
goto out;
EC_KEY_METHOD_get_sign(default_method, &sign, &sign_setup, NULL);
EC_KEY_METHOD_set_sign(ecdsa_method, sign, sign_setup,
tls_ecdsa_do_sign);
out:
return (ecdsa_method);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tls_verify.c,v 1.23 2023/05/11 07:35:27 tb Exp $ */
/* $OpenBSD: tls_verify.c,v 1.29 2023/11/22 18:23:09 op Exp $ */
/*
* Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
*
@ -94,15 +94,21 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
union tls_addr addrbuf;
int addrlen, type;
int count, i;
int rv = 0;
int critical = 0;
int rv = -1;
*alt_match = 0;
*alt_exists = 0;
altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
NULL, NULL);
if (altname_stack == NULL)
return 0;
altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name, &critical,
NULL);
if (altname_stack == NULL) {
if (critical != -1) {
tls_set_errorx(ctx, "error decoding subjectAltName");
goto err;
}
goto done;
}
if (inet_pton(AF_INET, name, &addrbuf) == 1) {
type = GEN_IPADD;
@ -142,8 +148,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
"NUL byte in subjectAltName, "
"probably a malicious certificate",
name);
rv = -1;
break;
goto err;
}
/*
@ -156,13 +161,12 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
"error verifying name '%s': "
"a dNSName of \" \" must not be "
"used", name);
rv = -1;
break;
goto err;
}
if (tls_match_name(data, name) == 0) {
*alt_match = 1;
break;
goto done;
}
} else {
#ifdef DEBUG
@ -183,8 +187,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
tls_set_errorx(ctx,
"Unexpected negative length for an "
"IP address: %d", datalen);
rv = -1;
break;
goto err;
}
/*
@ -194,11 +197,15 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
if (datalen == addrlen &&
memcmp(data, &addrbuf, addrlen) == 0) {
*alt_match = 1;
break;
goto done;
}
}
}
done:
rv = 0;
err:
sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free);
return rv;
}
@ -207,10 +214,13 @@ static int
tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
int *cn_match)
{
unsigned char *utf8_bytes = NULL;
X509_NAME *subject_name;
char *common_name = NULL;
union tls_addr addrbuf;
int common_name_len;
ASN1_STRING *data;
int lastpos = -1;
int rv = -1;
*cn_match = 0;
@ -219,29 +229,65 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
if (subject_name == NULL)
goto done;
common_name_len = X509_NAME_get_text_by_NID(subject_name,
NID_commonName, NULL, 0);
if (common_name_len < 0)
lastpos = X509_NAME_get_index_by_NID(subject_name,
NID_commonName, lastpos);
if (lastpos == -1)
goto done;
common_name = calloc(common_name_len + 1, 1);
if (common_name == NULL) {
tls_set_error(ctx, "out of memory");
if (lastpos < 0)
goto err;
if (X509_NAME_get_index_by_NID(subject_name, NID_commonName, lastpos)
!= -1) {
/*
* Having multiple CN's is possible, and even happened back in
* the glory days of mullets and Hammer pants. In anything like
* a modern TLS cert, CN is as close to deprecated as it gets,
* and having more than one is bad. We therefore fail if we have
* more than one CN fed to us in the subject, treating the
* certificate as hostile.
*/
tls_set_errorx(ctx, "error verifying name '%s': "
"Certificate subject contains multiple Common Name fields, "
"probably a malicious or malformed certificate", name);
goto err;
}
X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name,
common_name_len + 1);
/* NUL bytes in CN? */
if (common_name_len < 0 ||
(size_t)common_name_len != strlen(common_name)) {
data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name,
lastpos));
/*
* Fail if we cannot encode the CN bytes as UTF-8.
*/
if ((common_name_len = ASN1_STRING_to_UTF8(&utf8_bytes, data)) < 0) {
tls_set_errorx(ctx, "error verifying name '%s': "
"Common Name field cannot be encoded as a UTF-8 string, "
"probably a malicious certificate", name);
goto err;
}
/*
* Fail if the CN is of invalid length. RFC 5280 specifies that a CN
* must be between 1 and 64 bytes long.
*/
if (common_name_len < 1 || common_name_len > 64) {
tls_set_errorx(ctx, "error verifying name '%s': "
"Common Name field has invalid length, "
"probably a malicious certificate", name);
goto err;
}
/*
* Fail if the resulting text contains a NUL byte.
*/
if (memchr(utf8_bytes, 0, common_name_len) != NULL) {
tls_set_errorx(ctx, "error verifying name '%s': "
"NUL byte in Common Name field, "
"probably a malicious certificate", name);
goto err;
}
common_name = strndup(utf8_bytes, common_name_len);
if (common_name == NULL) {
tls_set_error(ctx, "out of memory");
goto err;
}
/*
* We don't want to attempt wildcard matching against IP addresses,
* so perform a simple comparison here.
@ -260,6 +306,7 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
rv = 0;
err:
free(utf8_bytes);
free(common_name);
return rv;
}

18
configure vendored
View File

@ -447,9 +447,21 @@ elif [ ${HAVE_MACHINE_ENDIAN} -eq 1 ]; then
cat <<__HEREDOC__
#include <machine/endian.h>
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
__HEREDOC__
fi

View File

@ -60,7 +60,7 @@ Some things to keep in mind:
## mime.types
=> TREE/contrib/renew-certs contrib/mime.types
=> TREE/contrib/mime.types contrib/mime.types
A copy of OpenBSD' /usr/share/misc/mime.types to be used as
@ -97,4 +97,6 @@ To enable Syntastic checker, add to your vimrc:
let g:syntastic_gmid_checkers = ['gmid']
```
Obligatory screenshot:
=> vim-screenshot.png Screenshot of vim editing gmid.conf

View File

@ -2,9 +2,12 @@
## How can I report a bug, suggest a feature or send a patch?
Just drop an email to <gmid [at] omarpolo [dot] com> or open a GitHub issue/pull request.
Just drop an email to <gmid [at] omarpolo [dot] com> or open an issue/pull request on Codeberg or Github.
When reporting a bug please include the relevant information to reproduce the issue you're facing: your configuration file, the gmid version, and your distro.
=> https://codeberg.org/op/gmid Codeberg mirror
=> https://github.com/omar-polo/gmid GitHub mirror
When reporting a bug please include the relevant information to reproduce the issue you're facing: your configuration file, the gmid version, and your operating system or distro at least.
## How can I define the right MIME types for my files?
@ -22,54 +25,34 @@ types {
```
## CGI scripts don't work
## How to run CGI scripts?
There may be various reasons for it
As of gmid 2.0, to run CGI scripts an external program like fcgiwrap or slowcgi are needed.
* make sure the `cgi' rule in the `server' block matches the CGI script
* if using a chroot, make sure that all the libraries and executable are available inside the chroot (e.g. sh, python, perl, ...)
From the gmid side, one `fastcgi' block needs to be defined with the `socket' pointing at the fcgiwrap or slowcgi socket inside the chroot. The `SCRIPT_NAME' parameter pointing to the script path is often needed since gmid is unable to deduce the right path otherwise.
``` example configuration that runs a CGI via slowcgi
server "example.com" {
listen on *
cert "/path/to/cert"
key "/path/to/key"
## (linux) gmid doesn't seem to work / some tests are failing
gmid uses a security feature of the linux kernel called "seccomp".
Seccomp allows to define a set of allowed system calls (in layman's term "things that a program can do") and terminate the program if it attempts to do something else. While this is cool, sometimes the kernel developers may add some new system calls, or the libraries used by gmid could start using others system calls to achieve the same thing, so the seccomp filter may need adjustments over the time.
Simptoms of a possible failure due seccomp are gmid not seeming to work or hangs/failure as soon as some features of gmid (cgi scripts, reverse proxying, ...) are used.
To debug a (supposed) seccomp issue, decomment SC_DEBUG in sandbox.c
```
/* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
/* #define SC_DEBUG */
location "/cgi-bin/hello" {
fastcgi {
socket "/run/slowcgi.sock"
param SCRIPT_NAME = "/cgi-bin/hello"
}
}
}
```
so that it becomes
Then, fcgiwrap or slowcgi need to be started as well.
```
/* uncomment to enable debugging. ONLY FOR DEVELOPMENT */
#define SC_DEBUG
```
then recompile gmid and run the regress suite:
## How to automatically renew the certificates?
```
$ make regress
```
It depends on how the certificate were obtained. For example, if acme-client or certbot are used they provide their own mechanism to renew the certs and restart daemons.
If it's indeed a seccomp failure it should print something like the following among the other logs:
In case of a self-signed certificate, contrib/renew-certs could help. It's meant to be scheduled periodically with cron(8) and automatically generate a new key and certificate when one is about to expire and restarts gmid.
```
unexpected system call (arch:...,syscall:... @ ...)
```
Please attach the `make regress' output, the distro you're using and `uname -m' in the bug report (either on github or via email.)
If you're technically inclined, you could also try to write a patch to fix the issue and attach it to the bug report: receiving patches makes me really happy!
You can get the syscall name from the numbers by looking in the linux kernel headers. Unfortunately, the exact position differs from distro to distro, but they should be somewhere under /usr/include. Once you know the name of the syscall, you can add it to the list in the `filter' array and reiterate the whole procedure until it works.
Providing a patch *is not expected* and *is not a requirement* either. It's just nice to do if you have the skill, time and patience to do so.
Don't forget to comment SC_DEBUG after playing with it if you're gonna use the executable.
=> TREE/contrib/renew-certs contrib/renew-certs

View File

@ -2,25 +2,15 @@
> A Gemini server
## Features
gmid is a full-featured Gemini server written with security in mind. It can serve static files, has an optional FastCGI and proxying support and a rich configuration syntax.
* sandboxed by default on OpenBSD, FreeBSD and Linux
* able to reload the configuration on-the-fly without loosing connections
* punycode and IRI support
* reverse proxying
* CGI and FastCGI support
* virtual hosts and per-location rules
* low memory footprint
* event-based asynchronous I/O model
* rich configuration file
gmid also bundles a small gemini client called gg (gemini get), a small command-line server for quick testing called gemexp and a titan implementation.
gmid also bundles a small gemini client called gg (gemini get), a stripped-down server for quick testing called gemexp and a titan implementation.
=> gmid.8.MANEXT gmid(8) manpage
=> gmid.conf.5.MANEXT gmid.conf(5) manpage
=> gg.1.MANEXT gg(1) manpage
=> gemexp.1.MANEXT gemexp(1) manpage
=> titan.1.MANEXT titan(1) manpage
=> gmid.8.MANEXT gmid(8) - Gemini server
=> gmid.conf.5.MANEXT gmid.conf(5) - gmid configuration file
=> gg.1.MANEXT gg(1) - gemini client
=> gemexp.1.MANEXT gemexp(1) - export a directory over Gemini
=> titan.1.MANEXT titan(1) - Titan client
## Install
@ -39,7 +29,7 @@ Otherwise, compile it from source: its easy and takes less than a minute on a
The dependencies are:
* libevent
* OpenSSL/LibreSSL
* LibreSSL or OpenSSL
* yacc or GNU bison
Once all the dependencies are installed, building is as easy as:
@ -53,7 +43,7 @@ $ make
$ sudo make install # eventually
```
A SHA256 file is available. However, that only checks for accidental corruption: you can use signify (SHA256.sig and the public key gmid-CURV.pub). The signify public key for the next release gmid-NEXTV.pub is also included.
A SHA256 file is available. However, it only checks for accidental corruption. You can use signify (SHA256.sig and the public key gmid-CURV.pub) to cryptographically verify the downloaded tarball. The signify public key for the next release gmid-NEXTV.pub is also included.
=> GITHUB/releases/download/VERS/SHA256 SHA256
=> GITHUB/releases/download/VERS/SHA256.sig SHA256.sig

View File

@ -1,27 +1,14 @@
# gmid quickstart guide
gmid can be run in two different modes:
The aim of this “quickstart” guide is to get your capsule up and running.
* configless: a quick way to serve a directory tree from the shell, useful for testing purposes
* daemon mode: gmid reads the configuration file and runs in the background
To run gmid in the “configless” mode, just type:
```serve a directory tree from the shell
$ gmid path/to/dir
```
gmid will then generate a certificate inside ~/.local/share/gmid and serve the given directory locally.
## Setting up a capsule with gmid
To host a Gemini capsule you need to run gmid in “daemon” mode, and so a configuration file is needed. The format of the configuration file is described in the manpage and is quite flexible, but something like the following should be enough to start:
gmid needs a configuration file to operate. The format is quite flexible and carefully described in the gmid.conf(5) manpage, but to start this should be enough:
```sample configuration file
# /etc/gmid.conf
server "example.com" {
listen on * port 1965
cert "/etc/ssl/example.com.pem"
key "/etc/ssl/private/example.com.key"
@ -30,6 +17,8 @@ server "example.com" {
}
```
This will have gmid listening on any address on port 1965 and serving the directory /var/gemini/example.com.
A TLS certificate is also needed. There are many way to obtain one (acme-client, certbot, ...) but within the Geminispace is common to use self-signed ones.
One way to generate self-signed certificates is to use openssl(1), but contrib/gencert is easier to use:
@ -118,7 +107,7 @@ Its a common practice for system daemons to chroot themselves into a director
A chroot on UNIX-like OS is an operation that changes the “apparent” root directory (i.e. the “/”) from the current process and its child. Think of it like imprisoning a process into a directory and never letting it escape until it terminates.
Using a chroot may complicate the use of CGI scripts, because then all the dependencies of the scripts (sh, perl, libraries…) need to be installed inside the chroot too. For this very reason gmid supports FastCGI.
Using a chroot may complicate the setup since eventual FastCGI socket or files needed for DNS resolution need to be installed or copied inside the chroot too.
The chroot feature requires a dedicate user, see the previous section.
@ -144,6 +133,7 @@ user "gmid"
chroot "/var/gemini"
server "example.com" {
listen on *
cert "/etc/ssl/example.com.pem"
key "/etc/ssl/example.com.key"
root "/example.com"