diff options
author | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2016-05-01 00:32:38 +0000 |
---|---|---|
committer | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2016-05-01 00:32:38 +0000 |
commit | 344e69804391bf056890fd0fd4c077645230f565 (patch) | |
tree | 5171ee19b2630895ee269bad7a2f3042d037ddf4 | |
parent | f92aaf9e63830deb6f727004e6d0e1eba5d420de (diff) |
convert ldapd to use the libtls api, bringing in a copy of the evbuffer_tls
code from syslogd.
ok beck@ benno@
-rw-r--r-- | usr.sbin/ldapd/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/ldapd/conn.c | 55 | ||||
-rw-r--r-- | usr.sbin/ldapd/evbuffer_tls.c | 350 | ||||
-rw-r--r-- | usr.sbin/ldapd/evbuffer_tls.h | 37 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldapd.c | 4 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldapd.h | 41 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldape.c | 22 | ||||
-rw-r--r-- | usr.sbin/ldapd/parse.y | 97 | ||||
-rw-r--r-- | usr.sbin/ldapd/ssl.c | 565 | ||||
-rw-r--r-- | usr.sbin/ldapd/ssl_privsep.c | 172 |
10 files changed, 559 insertions, 792 deletions
diff --git a/usr.sbin/ldapd/Makefile b/usr.sbin/ldapd/Makefile index d35945bbef8..5d2aea00428 100644 --- a/usr.sbin/ldapd/Makefile +++ b/usr.sbin/ldapd/Makefile @@ -1,15 +1,15 @@ -# $OpenBSD: Makefile,v 1.12 2014/07/16 20:07:03 okan Exp $ +# $OpenBSD: Makefile,v 1.13 2016/05/01 00:32:37 jmatthew Exp $ PROG= ldapd MAN= ldapd.8 ldapd.conf.5 SRCS= ber.c log.c control.c \ util.c ldapd.c ldape.c conn.c attributes.c namespace.c \ btree.c filter.c search.c parse.y \ - auth.c modify.c index.c ssl.c ssl_privsep.c \ + auth.c modify.c index.c evbuffer_tls.c \ validate.c uuid.c schema.c imsgev.c syntax.c matching.c -LDADD= -levent -lssl -lcrypto -lz -lutil -DPADD= ${LIBEVENT} ${LIBCRYPTO} ${LIBSSL} ${LIBZ} ${LIBUTIL} +LDADD= -ltls -levent -lz -lutil +DPADD= ${LIBEVENT} ${LIBTLS} ${LIBCRYPTO} ${LIBSSL} ${LIBZ} ${LIBUTIL} CFLAGS+= -I${.CURDIR} -g CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations diff --git a/usr.sbin/ldapd/conn.c b/usr.sbin/ldapd/conn.c index 0a4a02ad323..728c75d69f1 100644 --- a/usr.sbin/ldapd/conn.c +++ b/usr.sbin/ldapd/conn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conn.c,v 1.12 2015/11/02 06:32:51 jmatthew Exp $ */ +/* $OpenBSD: conn.c,v 1.13 2016/05/01 00:32:37 jmatthew Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -26,6 +26,7 @@ #include "ldapd.h" int conn_dispatch(struct conn *conn); +int conn_tls_init(struct conn *); unsigned long ldap_application(struct ber_element *elm); struct conn_list conn_list; @@ -61,7 +62,7 @@ conn_close(struct conn *conn) /* Cancel any queued requests on this connection. */ namespace_cancel_conn(conn); - ssl_session_destroy(conn); + tls_free(conn->tls); TAILQ_REMOVE(&conn_list, conn, next); ber_free(&conn->ber); @@ -225,9 +226,8 @@ conn_write(struct bufferevent *bev, void *data) conn_close(conn); else if (conn->s_flags & F_STARTTLS) { conn->s_flags &= ~F_STARTTLS; - bufferevent_free(conn->bev); - conn->bev = NULL; - ssl_session_init(conn); + if (conn_tls_init(conn) == -1) + conn_close(conn); } } @@ -296,24 +296,22 @@ conn_accept(int fd, short event, void *data) goto giveup; } conn->ber.fd = -1; - conn->s_l = l; ber_set_application(&conn->ber, ldap_application); conn->fd = afd; conn->listener = l; - if (l->flags & F_LDAPS) { - ssl_session_init(conn); - } else { - conn->bev = bufferevent_new(afd, conn_read, conn_write, - conn_err, conn); - if (conn->bev == NULL) { - log_warn("conn_accept: bufferevent_new"); - free(conn); - goto giveup; - } - bufferevent_enable(conn->bev, EV_READ); - bufferevent_settimeout(conn->bev, 0, 60); + conn->bev = bufferevent_new(afd, conn_read, conn_write, + conn_err, conn); + if (conn->bev == NULL) { + log_warn("conn_accept: bufferevent_new"); + free(conn); + goto giveup; } + bufferevent_enable(conn->bev, EV_READ); + bufferevent_settimeout(conn->bev, 0, 60); + if (l->flags & F_LDAPS) + if (conn_tls_init(conn) == -1) + conn_close(conn); TAILQ_INIT(&conn->searches); TAILQ_INSERT_HEAD(&conn_list, conn, next); @@ -366,3 +364,24 @@ conn_close_any() return -1; } + +int +conn_tls_init(struct conn *conn) +{ + struct listener *l = conn->listener; + + if (!(l->flags & F_SSL)) + return 0; + + log_debug("conn_tls_init: switching to TLS"); + + if (tls_accept_socket(l->tls, &conn->tls, conn->fd) < 0) { + log_debug("tls_accept_socket failed"); + return -1; + } + + conn->s_flags |= F_SECURE; + buffertls_set(&conn->buftls, conn->bev, conn->tls, conn->fd); + buffertls_accept(&conn->buftls, conn->fd); + return 0; +} diff --git a/usr.sbin/ldapd/evbuffer_tls.c b/usr.sbin/ldapd/evbuffer_tls.c new file mode 100644 index 00000000000..b0d0e2ee771 --- /dev/null +++ b/usr.sbin/ldapd/evbuffer_tls.c @@ -0,0 +1,350 @@ +/* $OpenBSD: evbuffer_tls.c,v 1.1 2016/05/01 00:32:37 jmatthew Exp $ */ + +/* + * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu> + * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <errno.h> +#include <event.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <tls.h> + +#include "evbuffer_tls.h" + +/* prototypes */ + +void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); +static void buffertls_readcb(int, short, void *); +static void buffertls_writecb(int, short, void *); +static void buffertls_handshakecb(int, short, void *); +int evtls_read(struct evbuffer *, int, int, struct tls *); +int evtls_write(struct evbuffer *, int, struct tls *); + +static int +bufferevent_add(struct event *ev, int timeout) +{ + struct timeval tv, *ptv = NULL; + + if (timeout) { + timerclear(&tv); + tv.tv_sec = timeout; + ptv = &tv; + } + + return (event_add(ev, ptv)); +} + +static void +buffertls_readcb(int fd, short event, void *arg) +{ + struct buffertls *buftls = arg; + struct bufferevent *bufev = buftls->bt_bufev; + struct tls *ctx = buftls->bt_ctx; + int res = 0; + short what = EVBUFFER_READ; + size_t len; + int howmuch = -1; + + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; + goto error; + } + + /* + * If we have a high watermark configured then we don't want to + * read more data than would make us reach the watermark. + */ + if (bufev->wm_read.high != 0) { + howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input); + /* we might have lowered the watermark, stop reading */ + if (howmuch <= 0) { + struct evbuffer *buf = bufev->input; + event_del(&bufev->ev_read); + evbuffer_setcb(buf, + bufferevent_read_pressure_cb, bufev); + return; + } + } + + res = evtls_read(bufev->input, fd, howmuch, ctx); + switch (res) { + case TLS_WANT_POLLIN: + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + return; + case TLS_WANT_POLLOUT: + event_del(&bufev->ev_write); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_readcb, + buftls); + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + return; + case -1: + what |= EVBUFFER_ERROR; + break; + case 0: + what |= EVBUFFER_EOF; + break; + } + if (res <= 0) + goto error; + + event_del(&bufev->ev_write); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); + if (bufev->enabled & EV_READ) + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + + /* See if this callbacks meets the water marks */ + len = EVBUFFER_LENGTH(bufev->input); + if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) + return; + if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { + struct evbuffer *buf = bufev->input; + event_del(&bufev->ev_read); + + /* Now schedule a callback for us when the buffer changes */ + evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); + } + + /* Invoke the user callback - must always be called last */ + if (bufev->readcb != NULL) + (*bufev->readcb)(bufev, bufev->cbarg); + return; + + error: + (*bufev->errorcb)(bufev, what, bufev->cbarg); +} + +static void +buffertls_writecb(int fd, short event, void *arg) +{ + struct buffertls *buftls = arg; + struct bufferevent *bufev = buftls->bt_bufev; + struct tls *ctx = buftls->bt_ctx; + int res = 0; + short what = EVBUFFER_WRITE; + + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; + goto error; + } + + if (EVBUFFER_LENGTH(bufev->output) != 0) { + res = evtls_write(bufev->output, fd, ctx); + switch (res) { + case TLS_WANT_POLLIN: + event_del(&bufev->ev_read); + event_set(&bufev->ev_read, fd, EV_READ, + buffertls_writecb, buftls); + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + return; + case TLS_WANT_POLLOUT: + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + return; + case -1: + what |= EVBUFFER_ERROR; + break; + case 0: + what |= EVBUFFER_EOF; + break; + } + if (res <= 0) + goto error; + } + + event_del(&bufev->ev_read); + event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); + if (bufev->enabled & EV_READ) + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + + /* + * Invoke the user callback if our buffer is drained or below the + * low watermark. + */ + if (bufev->writecb != NULL && + EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) + (*bufev->writecb)(bufev, bufev->cbarg); + + return; + + error: + (*bufev->errorcb)(bufev, what, bufev->cbarg); +} + +static void +buffertls_handshakecb(int fd, short event, void *arg) +{ + struct buffertls *buftls = arg; + struct bufferevent *bufev = buftls->bt_bufev; + struct tls *ctx = buftls->bt_ctx; + int res = 0; + short what = EVBUFFER_HANDSHAKE; + + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; + goto error; + } + + res = tls_handshake(ctx); + switch (res) { + case TLS_WANT_POLLIN: + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + return; + case TLS_WANT_POLLOUT: + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + return; + case -1: + what |= EVBUFFER_ERROR; + break; + } + if (res < 0) + goto error; + + /* Handshake was successful, change to read and write callback. */ + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); + event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); + if (bufev->enabled & EV_READ) + bufferevent_add(&bufev->ev_read, bufev->timeout_read); + if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE) + bufferevent_add(&bufev->ev_write, bufev->timeout_write); + + return; + + error: + (*bufev->errorcb)(bufev, what, bufev->cbarg); +} + +void +buffertls_set(struct buffertls *buftls, struct bufferevent *bufev, + struct tls *ctx, int fd) +{ + bufferevent_setfd(bufev, fd); + event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); + buftls->bt_bufev = bufev; + buftls->bt_ctx = ctx; +} + +void +buffertls_accept(struct buffertls *buftls, int fd) +{ + struct bufferevent *bufev = buftls->bt_bufev; + + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); + event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb, + buftls); + bufferevent_add(&bufev->ev_read, bufev->timeout_read); +} + +void +buffertls_connect(struct buffertls *buftls, int fd) +{ + struct bufferevent *bufev = buftls->bt_bufev; + + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); + event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls); + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb, + buftls); + bufferevent_add(&bufev->ev_write, bufev->timeout_write); +} + +/* + * Reads data from a file descriptor into a buffer. + */ + +#define EVBUFFER_MAX_READ 4096 + +int +evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx) +{ + u_char *p; + size_t oldoff = buf->off; + int n = EVBUFFER_MAX_READ; + + if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) { + n = EVBUFFER_MAX_READ; + } else if (n > EVBUFFER_MAX_READ && n > howmuch) { + /* + * It's possible that a lot of data is available for + * reading. We do not want to exhaust resources + * before the reader has a chance to do something + * about it. If the reader does not tell us how much + * data we should read, we artifically limit it. + */ + if ((size_t)n > buf->totallen << 2) + n = buf->totallen << 2; + if (n < EVBUFFER_MAX_READ) + n = EVBUFFER_MAX_READ; + } + if (howmuch < 0 || howmuch > n) + howmuch = n; + + /* If we don't have FIONREAD, we might waste some space here */ + if (evbuffer_expand(buf, howmuch) == -1) + return (-1); + + /* We can append new data at this point */ + p = buf->buffer + buf->off; + + n = tls_read(ctx, p, howmuch); + if (n <= 0) + return (n); + + buf->off += n; + + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + + return (n); +} + +int +evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx) +{ + int n; + + n = tls_write(ctx, buffer->buffer, buffer->off); + if (n <= 0) + return (n); + evbuffer_drain(buffer, n); + + return (n); +} diff --git a/usr.sbin/ldapd/evbuffer_tls.h b/usr.sbin/ldapd/evbuffer_tls.h new file mode 100644 index 00000000000..2f990174e19 --- /dev/null +++ b/usr.sbin/ldapd/evbuffer_tls.h @@ -0,0 +1,37 @@ +/* $OpenBSD: evbuffer_tls.h,v 1.1 2016/05/01 00:32:37 jmatthew Exp $ */ + +/* + * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@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. + */ + +#ifndef _EVBUFFER_TLS_H_ +#define _EVBUFFER_TLS_H_ + +#define EVBUFFER_HANDSHAKE 0x04 + +struct bufferevent; +struct tls; + +struct buffertls { + struct bufferevent *bt_bufev; + struct tls *bt_ctx; +}; + +void buffertls_set(struct buffertls *, struct bufferevent *, struct tls *, + int); +void buffertls_accept(struct buffertls *, int); +void buffertls_connect(struct buffertls *, int); + +#endif /* _EVBUFFER_TLS_H_ */ diff --git a/usr.sbin/ldapd/ldapd.c b/usr.sbin/ldapd/ldapd.c index d8c723d87cc..b41eb2dac2f 100644 --- a/usr.sbin/ldapd/ldapd.c +++ b/usr.sbin/ldapd/ldapd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldapd.c,v 1.19 2016/02/04 12:48:06 jca Exp $ */ +/* $OpenBSD: ldapd.c,v 1.20 2016/05/01 00:32:37 jmatthew Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -163,7 +163,7 @@ main(int argc, char *argv[]) log_verbose(verbose); stats.started_at = time(0); - ssl_init(); + tls_init(); if (parse_config(conffile) != 0) exit(2); diff --git a/usr.sbin/ldapd/ldapd.h b/usr.sbin/ldapd/ldapd.h index d6b9b8a981d..2cb4050f4dc 100644 --- a/usr.sbin/ldapd/ldapd.h +++ b/usr.sbin/ldapd/ldapd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldapd.h,v 1.25 2015/11/02 06:32:51 jmatthew Exp $ */ +/* $OpenBSD: ldapd.h,v 1.26 2016/05/01 00:32:37 jmatthew Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -30,11 +30,13 @@ #include <limits.h> #include <pwd.h> #include <stdarg.h> +#include <tls.h> #include "aldap.h" #include "schema.h" #include "btree.h" #include "imsgev.h" +#include "evbuffer_tls.h" #define CONFFILE "/etc/ldapd.conf" #define LDAPD_USER "_ldapd" @@ -203,7 +205,7 @@ struct listener { struct event evt; char ssl_cert_name[PATH_MAX]; struct ssl *ssl; - void *ssl_ctx; + struct tls *tls; TAILQ_ENTRY(listener) entry; }; TAILQ_HEAD(listenerlist, listener); @@ -223,12 +225,8 @@ struct conn { struct listener *listener; /* where it connected from */ /* SSL support */ - struct event s_ev; - struct timeval s_tv; - struct listener *s_l; - void *s_ssl; - unsigned char *s_buf; - int s_buflen; + struct tls *tls; + struct buffertls buftls; unsigned int s_flags; }; TAILQ_HEAD(conn_list, conn) conn_list; @@ -236,11 +234,12 @@ TAILQ_HEAD(conn_list, conn) conn_list; struct ssl { SPLAY_ENTRY(ssl) ssl_nodes; char ssl_name[PATH_MAX]; - char *ssl_cert; - off_t ssl_cert_len; - char *ssl_key; - off_t ssl_key_len; + uint8_t *ssl_cert; + size_t ssl_cert_len; + uint8_t *ssl_key; + size_t ssl_key_len; uint8_t flags; + struct tls_config *config; }; struct ldapd_config @@ -461,6 +460,9 @@ int authorized(struct conn *conn, struct namespace *ns, /* parse.y */ int parse_config(char *filename); int cmdline_symset(char *s); +int ssl_cmp(struct ssl *, struct ssl *); +SPLAY_PROTOTYPE(ssltree, ssl, ssl_nodes, ssl_cmp); + /* log.c */ void log_init(int); @@ -499,21 +501,6 @@ int unindex_entry(struct namespace *ns, struct btval *dn, int index_to_dn(struct namespace *ns, struct btval *indx, struct btval *dn); -/* ssl.c */ -void ssl_init(void); -void ssl_transaction(struct conn *); - -void ssl_session_init(struct conn *); -void ssl_session_destroy(struct conn *); -int ssl_load_certfile(struct ldapd_config *, const char *, u_int8_t); -void ssl_setup(struct ldapd_config *, struct listener *); -int ssl_cmp(struct ssl *, struct ssl *); -SPLAY_PROTOTYPE(ssltree, ssl, ssl_nodes, ssl_cmp); - -/* ssl_privsep.c */ -int ssl_ctx_use_private_key(void *, char *, off_t); -int ssl_ctx_use_certificate_chain(void *, char *, off_t); - /* validate.c */ int validate_entry(const char *dn, struct ber_element *entry, int relax); diff --git a/usr.sbin/ldapd/ldape.c b/usr.sbin/ldapd/ldape.c index bb681a336dc..36559e1954b 100644 --- a/usr.sbin/ldapd/ldape.c +++ b/usr.sbin/ldapd/ldape.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldape.c,v 1.23 2015/12/24 17:47:57 mmcc Exp $ */ +/* $OpenBSD: ldape.c,v 1.24 2016/05/01 00:32:37 jmatthew Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -341,6 +341,7 @@ ldape(struct passwd *pw, char *csockpath, int pipe_parent2ldap[2]) struct event ev_sigterm; struct event ev_sigchld; struct event ev_sighup; + struct ssl key; char host[128]; mode_t old_umask = 0; @@ -424,7 +425,24 @@ ldape(struct passwd *pw, char *csockpath, int pipe_parent2ldap[2]) event_add(&l->ev, NULL); evtimer_set(&l->evt, conn_accept, l); - ssl_setup(conf, l); + if (l->flags & F_SSL) { + if (strlcpy(key.ssl_name, l->ssl_cert_name, + sizeof(key.ssl_name)) >= sizeof(key.ssl_name)) + fatal("ldape: certificate name truncated"); + + l->ssl = SPLAY_FIND(ssltree, conf->sc_ssl, &key); + if (l->ssl == NULL) + fatal("ldape: certificate tree corrupted"); + + l->tls = tls_server(); + if (l->tls == NULL) + fatal("ldape: couldn't allocate tls context"); + + if (tls_configure(l->tls, l->ssl->config)) { + log_warn("ldape: %s", tls_error(l->tls)); + fatal("ldape: couldn't configure tls"); + } + } } TAILQ_FOREACH(ns, &conf->namespaces, next) { diff --git a/usr.sbin/ldapd/parse.y b/usr.sbin/ldapd/parse.y index 6bbb454397a..aec1d12ab28 100644 --- a/usr.sbin/ldapd/parse.y +++ b/usr.sbin/ldapd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.16 2014/11/20 05:51:20 jsg Exp $ */ +/* $OpenBSD: parse.y,v 1.17 2016/05/01 00:32:37 jmatthew Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org> @@ -77,6 +77,7 @@ int host(const char *, const char *, struct listenerlist *, int, in_port_t, u_int8_t); int interface(const char *, const char *, struct listenerlist *, int, in_port_t, u_int8_t); +int load_certfile(struct ldapd_config *, const char *, u_int8_t); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -91,6 +92,8 @@ char *symget(const char *); struct ldapd_config *conf; +SPLAY_GENERATE(ssltree, ssl, ssl_nodes, ssl_cmp); + static struct aci *mk_aci(int type, int rights, enum scope scope, char *target, char *subject); @@ -181,7 +184,7 @@ conf_main : LISTEN ON STRING port ssl certname { cert = ($6 != NULL) ? $6 : $3; if (($5 == F_STARTTLS || $5 == F_LDAPS) && - ssl_load_certfile(conf, cert, F_SCERT) < 0) { + load_certfile(conf, cert, F_SCERT) < 0) { yyerror("cannot load certificate: %s", cert); free($6); free($3); @@ -1167,3 +1170,93 @@ namespace_new(const char *suffix) return ns; } +int +ssl_cmp(struct ssl *s1, struct ssl *s2) +{ + return (strcmp(s1->ssl_name, s2->ssl_name)); +} + +int +load_certfile(struct ldapd_config *env, const char *name, u_int8_t flags) +{ + struct ssl *s; + struct ssl key; + char certfile[PATH_MAX]; + + if (strlcpy(key.ssl_name, name, sizeof(key.ssl_name)) + >= sizeof(key.ssl_name)) { + log_warn("load_certfile: certificate name truncated"); + return -1; + } + + s = SPLAY_FIND(ssltree, env->sc_ssl, &key); + if (s != NULL) { + s->flags |= flags; + return 0; + } + + if ((s = calloc(1, sizeof(*s))) == NULL) + fatal(NULL); + + s->flags = flags; + (void)strlcpy(s->ssl_name, key.ssl_name, sizeof(s->ssl_name)); + + s->config = tls_config_new(); + if (s->config == NULL) + goto err; + + tls_config_set_protocols(s->config, TLS_PROTOCOLS_ALL); + if (tls_config_set_ciphers(s->config, "compat")) { + log_warn("load_certfile: failed to set tls ciphers: %s", + tls_config_error(s->config)); + goto err; + } + + if ((name[0] == '/' && + !bsnprintf(certfile, sizeof(certfile), "%s.crt", name)) || + !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.crt", + name)) { + log_warn("load_certfile: path truncated"); + goto err; + } + + log_debug("loading certificate file %s", certfile); + s->ssl_cert = tls_load_file(certfile, &s->ssl_cert_len, NULL); + if (s->ssl_cert == NULL) + goto err; + + if (tls_config_set_cert_mem(s->config, s->ssl_cert, s->ssl_cert_len)) { + log_warn("load_certfile: failed to set tls certificate: %s", + tls_config_error(s->config)); + goto err; + } + + if ((name[0] == '/' && + !bsnprintf(certfile, sizeof(certfile), "%s.key", name)) || + !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.key", + name)) { + log_warn("load_certfile: path truncated"); + goto err; + } + + log_debug("loading key file %s", certfile); + s->ssl_key = tls_load_file(certfile, &s->ssl_key_len, NULL); + if (s->ssl_key == NULL) + goto err; + + if (tls_config_set_key_mem(s->config, s->ssl_key, s->ssl_key_len)) { + log_warn("load_certfile: failed to set tls key: %s", + tls_config_error(s->config)); + goto err; + } + + SPLAY_INSERT(ssltree, env->sc_ssl, s); + + return (0); +err: + free(s->ssl_cert); + free(s->ssl_key); + tls_config_free(s->config); + free(s); + return (-1); +} diff --git a/usr.sbin/ldapd/ssl.c b/usr.sbin/ldapd/ssl.c deleted file mode 100644 index e723e2af809..00000000000 --- a/usr.sbin/ldapd/ssl.c +++ /dev/null @@ -1,565 +0,0 @@ -/* $OpenBSD: ssl.c,v 1.10 2015/12/30 15:59:55 benno Exp $ */ - -/* - * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> - * Copyright (c) 2008 Reyk Floeter <reyk@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 <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <ctype.h> -#include <event.h> -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <openssl/ssl.h> -#include <openssl/engine.h> -#include <openssl/err.h> -#include <openssl/dh.h> -#include <openssl/bn.h> - -#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) - -#include "ldapd.h" - -#define SSL_CIPHERS "HIGH:!aNULL" - -void ssl_error(const char *); -char *ssl_load_file(const char *, off_t *); -SSL_CTX *ssl_ctx_create(void); -void ssl_session_accept(int, short, void *); -void ssl_read(int, short, void *); -void ssl_write(int, short, void *); -int ssl_bufferevent_add(struct event *, int); - -DH *get_dh1024(void); -void ssl_set_ephemeral_key_exchange(SSL_CTX *, DH *); - -extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t, - size_t, void *); - -void -ssl_read(int fd, short event, void *p) -{ - struct bufferevent *bufev = p; - struct conn *s = bufev->cbarg; - int ret; - int ssl_err; - short what; - size_t len; - char rbuf[IBUF_READ_SIZE]; - int howmuch = IBUF_READ_SIZE; - - what = EVBUFFER_READ; - - if (event == EV_TIMEOUT) { - what |= EVBUFFER_TIMEOUT; - goto err; - } - - if (bufev->wm_read.high != 0) - howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high); - - ret = SSL_read(s->s_ssl, rbuf, howmuch); - if (ret <= 0) { - ssl_err = SSL_get_error(s->s_ssl, ret); - - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - goto retry; - case SSL_ERROR_WANT_WRITE: - goto retry; - default: - if (ret == 0) - what |= EVBUFFER_EOF; - else { - ssl_error("ssl_read"); - what |= EVBUFFER_ERROR; - } - goto err; - } - } - - if (evbuffer_add(bufev->input, rbuf, ret) == -1) { - what |= EVBUFFER_ERROR; - goto err; - } - - ssl_bufferevent_add(&bufev->ev_read, bufev->timeout_read); - - len = EVBUFFER_LENGTH(bufev->input); - if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) - return; - if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) { - struct evbuffer *buf = bufev->input; - event_del(&bufev->ev_read); - evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); - return; - } - - if (bufev->readcb != NULL) - (*bufev->readcb)(bufev, bufev->cbarg); - return; - -retry: - ssl_bufferevent_add(&bufev->ev_read, bufev->timeout_read); - return; - -err: - (*bufev->errorcb)(bufev, what, bufev->cbarg); -} - - -void -ssl_write(int fd, short event, void *p) -{ - struct bufferevent *bufev = p; - struct conn *s = bufev->cbarg; - int ret; - int ssl_err; - short what; - - what = EVBUFFER_WRITE; - - if (event == EV_TIMEOUT) { - what |= EV_TIMEOUT; - goto err; - } - - if (EVBUFFER_LENGTH(bufev->output)) { - if (s->s_buf == NULL) { - s->s_buflen = EVBUFFER_LENGTH(bufev->output); - if ((s->s_buf = malloc(s->s_buflen)) == NULL) { - what |= EVBUFFER_ERROR; - goto err; - } - memcpy(s->s_buf, EVBUFFER_DATA(bufev->output), - s->s_buflen); - } - - ret = SSL_write(s->s_ssl, s->s_buf, s->s_buflen); - if (ret <= 0) { - ssl_err = SSL_get_error(s->s_ssl, ret); - - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - goto retry; - case SSL_ERROR_WANT_WRITE: - goto retry; - default: - if (ret == 0) - what |= EVBUFFER_EOF; - else { - ssl_error("ssl_write"); - what |= EVBUFFER_ERROR; - } - goto err; - } - } - evbuffer_drain(bufev->output, ret); - } - if (s->s_buf != NULL) { - free(s->s_buf); - s->s_buf = NULL; - s->s_buflen = 0; - } - if (EVBUFFER_LENGTH(bufev->output) != 0) - ssl_bufferevent_add(&bufev->ev_write, bufev->timeout_write); - - if (bufev->writecb != NULL && - EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) - (*bufev->writecb)(bufev, bufev->cbarg); - return; - -retry: - if (s->s_buflen != 0) - ssl_bufferevent_add(&bufev->ev_write, bufev->timeout_write); - return; - -err: - if (s->s_buf != NULL) { - free(s->s_buf); - s->s_buf = NULL; - s->s_buflen = 0; - } - (*bufev->errorcb)(bufev, what, bufev->cbarg); -} - -int -ssl_bufferevent_add(struct event *ev, int timeout) -{ - struct timeval tv; - struct timeval *ptv = NULL; - - if (timeout) { - timerclear(&tv); - tv.tv_sec = timeout; - ptv = &tv; - } - - return (event_add(ev, ptv)); -} - -int -ssl_cmp(struct ssl *s1, struct ssl *s2) -{ - return (strcmp(s1->ssl_name, s2->ssl_name)); -} - -SPLAY_GENERATE(ssltree, ssl, ssl_nodes, ssl_cmp); - -char * -ssl_load_file(const char *name, off_t *len) -{ - struct stat st; - off_t size; - char *buf = NULL; - int fd; - - if ((fd = open(name, O_RDONLY)) == -1) - return (NULL); - if (fstat(fd, &st) != 0) - goto fail; - size = st.st_size; - if ((buf = calloc(1, size + 1)) == NULL) - goto fail; - if (read(fd, buf, size) != size) - goto fail; - close(fd); - - *len = size + 1; - return (buf); - -fail: - free(buf); - close(fd); - return (NULL); -} - -SSL_CTX * -ssl_ctx_create(void) -{ - SSL_CTX *ctx; - - ctx = SSL_CTX_new(SSLv23_method()); - if (ctx == NULL) { - ssl_error("ssl_ctx_create"); - fatal("ssl_ctx_create: could not create SSL context"); - } - - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); - SSL_CTX_set_timeout(ctx, LDAPD_SESSION_TIMEOUT); - SSL_CTX_set_options(ctx, SSL_OP_ALL); - SSL_CTX_set_options(ctx, - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - - if (!SSL_CTX_set_cipher_list(ctx, SSL_CIPHERS)) { - ssl_error("ssl_ctx_create"); - fatal("ssl_ctx_create: could not set cipher list"); - } - return (ctx); -} - -int -ssl_load_certfile(struct ldapd_config *env, const char *name, u_int8_t flags) -{ - struct ssl *s; - struct ssl key; - char certfile[PATH_MAX]; - - if (strlcpy(key.ssl_name, name, sizeof(key.ssl_name)) - >= sizeof(key.ssl_name)) { - log_warn("ssl_load_certfile: certificate name truncated"); - return -1; - } - - s = SPLAY_FIND(ssltree, env->sc_ssl, &key); - if (s != NULL) { - s->flags |= flags; - return 0; - } - - if ((s = calloc(1, sizeof(*s))) == NULL) - fatal(NULL); - - s->flags = flags; - (void)strlcpy(s->ssl_name, key.ssl_name, sizeof(s->ssl_name)); - - if ((name[0] == '/' && - !bsnprintf(certfile, sizeof(certfile), "%s.crt", name)) || - !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.crt", - name)) { - log_warn("ssl_load_certfile: path truncated"); - free(s); - return -1; - } - - log_debug("loading certificate file %s", certfile); - if ((s->ssl_cert = ssl_load_file(certfile, &s->ssl_cert_len)) == NULL) { - free(s); - return (-1); - } - - if ((name[0] == '/' && - !bsnprintf(certfile, sizeof(certfile), "%s.key", name)) || - !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.key", - name)) { - log_warn("ssl_load_certfile: path truncated"); - free(s->ssl_cert); - free(s); - return -1; - } - - log_debug("loading key file %s", certfile); - if ((s->ssl_key = ssl_load_file(certfile, &s->ssl_key_len)) == NULL) { - free(s->ssl_cert); - free(s); - return (-1); - } - - SPLAY_INSERT(ssltree, env->sc_ssl, s); - - return (0); -} - -void -ssl_init(void) -{ - SSL_library_init(); - SSL_load_error_strings(); - - OpenSSL_add_all_algorithms(); - - /* Init hardware crypto engines. */ - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -} - -void -ssl_setup(struct ldapd_config *env, struct listener *l) -{ - struct ssl key; - - if (!(l->flags & F_SSL)) - return; - - if (strlcpy(key.ssl_name, l->ssl_cert_name, sizeof(key.ssl_name)) - >= sizeof(key.ssl_name)) - fatal("ssl_setup: certificate name truncated"); - - if ((l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key)) == NULL) - fatal("ssl_setup: certificate tree corrupted"); - - l->ssl_ctx = ssl_ctx_create(); - - if (!ssl_ctx_use_certificate_chain(l->ssl_ctx, - l->ssl->ssl_cert, l->ssl->ssl_cert_len)) - goto err; - if (!ssl_ctx_use_private_key(l->ssl_ctx, - l->ssl->ssl_key, l->ssl->ssl_key_len)) - goto err; - - if (!SSL_CTX_check_private_key(l->ssl_ctx)) - goto err; - if (!SSL_CTX_set_session_id_context(l->ssl_ctx, - (const unsigned char *)l->ssl_cert_name, strlen(l->ssl_cert_name) + 1)) - goto err; - - ssl_set_ephemeral_key_exchange(l->ssl_ctx, get_dh1024()); - - log_debug("ssl_setup: ssl setup finished for listener: %p", l); - return; - -err: - SSL_CTX_free(l->ssl_ctx); - ssl_error("ssl_setup"); - fatal("ssl_setup: cannot set SSL up"); -} - -void -ssl_error(const char *where) -{ - unsigned long code; - char errbuf[128]; - extern int debug; - - if (!debug) - return; - for (; (code = ERR_get_error()) != 0 ;) { - ERR_error_string_n(code, errbuf, sizeof(errbuf)); - log_debug("SSL library error: %s: %s", where, errbuf); - } -} - -void -ssl_session_accept(int fd, short event, void *p) -{ - struct conn *s = p; - int ret; - int ssl_err; - - if (event == EV_TIMEOUT) { - log_debug("ssl_session_accept: session timed out"); - conn_close(s); - return; - } - - log_debug("ssl_session_accept: accepting client"); - ret = SSL_accept(s->s_ssl); - if (ret <= 0) { - ssl_err = SSL_get_error(s->s_ssl, ret); - - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - goto retry; - case SSL_ERROR_WANT_WRITE: - goto retry; - case SSL_ERROR_ZERO_RETURN: - case SSL_ERROR_SYSCALL: - if (ret == 0) { - conn_close(s); - return; - } - /* FALLTHROUGH */ - default: - ssl_error("ssl_session_accept"); - conn_close(s); - return; - } - } - - log_debug("ssl_session_accept: accepted ssl client"); - s->s_flags |= F_SECURE; - - s->bev = bufferevent_new(s->fd, conn_read, conn_write, conn_err, s); - if (s->bev == NULL) { - log_warn("ssl_session_accept: bufferevent_new"); - conn_close(s); - return; - } - bufferevent_settimeout(s->bev, 0, 60); - - event_set(&s->bev->ev_read, s->fd, EV_READ, ssl_read, s->bev); - event_set(&s->bev->ev_write, s->fd, EV_WRITE, ssl_write, s->bev); - bufferevent_enable(s->bev, EV_READ); - - return; -retry: - event_add(&s->s_ev, &s->s_tv); -} - -void -ssl_session_init(struct conn *s) -{ - struct listener *l; - SSL *ssl; - - l = s->s_l; - - if (!(l->flags & F_SSL)) - return; - - log_debug("ssl_session_init: switching to SSL"); - ssl = SSL_new(l->ssl_ctx); - if (ssl == NULL) - goto err; - - if (!SSL_set_ssl_method(ssl, SSLv23_server_method())) - goto err; - if (!SSL_set_fd(ssl, s->fd)) - goto err; - SSL_set_accept_state(ssl); - - s->s_ssl = ssl; - - s->s_tv.tv_sec = LDAPD_SESSION_TIMEOUT; - s->s_tv.tv_usec = 0; - event_set(&s->s_ev, s->fd, EV_READ|EV_TIMEOUT, ssl_session_accept, s); - event_add(&s->s_ev, &s->s_tv); - return; - - err: - SSL_free(ssl); - ssl_error("ssl_session_init"); -} - -void -ssl_session_destroy(struct conn *s) -{ - SSL_free(s->s_ssl); -} - -/* From OpenSSL's documentation: - * - * If "strong" primes were used to generate the DH parameters, it is - * not strictly necessary to generate a new key for each handshake - * but it does improve forward secrecy. - * - * -- gilles@ - */ -DH * -get_dh1024(void) -{ - DH *dh; - unsigned char dh1024_p[] = { - 0xAD,0x37,0xBB,0x26,0x75,0x01,0x27,0x75, - 0x06,0xB5,0xE7,0x1E,0x1F,0x2B,0xBC,0x51, - 0xC0,0xF4,0xEB,0x42,0x7A,0x2A,0x83,0x1E, - 0xE8,0xD1,0xD8,0xCC,0x9E,0xE6,0x15,0x1D, - 0x06,0x46,0x50,0x94,0xB9,0xEE,0xB6,0x89, - 0xB7,0x3C,0xAC,0x07,0x5E,0x29,0x37,0xCC, - 0x8F,0xDF,0x48,0x56,0x85,0x83,0x26,0x02, - 0xB8,0xB6,0x63,0xAF,0x2D,0x4A,0x57,0x93, - 0x6B,0x54,0xE1,0x8F,0x28,0x76,0x9C,0x5D, - 0x90,0x65,0xD1,0x07,0xFE,0x5B,0x05,0x65, - 0xDA,0xD2,0xE2,0xAF,0x23,0xCA,0x2F,0xD6, - 0x4B,0xD2,0x04,0xFE,0xDF,0x21,0x2A,0xE1, - 0xCD,0x1B,0x70,0x76,0xB3,0x51,0xA4,0xC9, - 0x2B,0x68,0xE3,0xDD,0xCB,0x97,0xDA,0x59, - 0x50,0x93,0xEE,0xDB,0xBF,0xC7,0xFA,0xA7, - 0x47,0xC4,0x4D,0xF0,0xC6,0x09,0x4A,0x4B - }; - unsigned char dh1024_g[] = { - 0x02 - }; - - if ((dh = DH_new()) == NULL) - return NULL; - - dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); - dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); - if (dh->p == NULL || dh->g == NULL) { - DH_free(dh); - return NULL; - } - - return dh; -} - -void -ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh) -{ - if (dh == NULL || !SSL_CTX_set_tmp_dh(ctx, dh)) - fatal("ssl_set_ephemeral_key_exchange: cannot set tmp dh"); -} diff --git a/usr.sbin/ldapd/ssl_privsep.c b/usr.sbin/ldapd/ssl_privsep.c deleted file mode 100644 index 0e55bae08d0..00000000000 --- a/usr.sbin/ldapd/ssl_privsep.c +++ /dev/null @@ -1,172 +0,0 @@ -/* $OpenBSD: ssl_privsep.c,v 1.4 2015/01/28 15:50:30 reyk Exp $ */ - -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -/* - * SSL operations needed when running in a privilege separated environment. - * Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard . - */ - -#include <sys/types.h> -#include <sys/uio.h> - -#include <unistd.h> -#include <stdio.h> - -#include <openssl/err.h> -#include <openssl/bio.h> -#include <openssl/objects.h> -#include <openssl/evp.h> -#include <openssl/x509.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> - -int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t); -int ssl_ctx_use_certificate_chain(SSL_CTX *, char *, off_t); - -int -ssl_ctx_use_private_key(SSL_CTX *ctx, char *buf, off_t len) -{ - int ret; - BIO *in; - EVP_PKEY *pkey; - - ret = 0; - - if ((in = BIO_new_mem_buf(buf, len)) == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB); - return 0; - } - - pkey = PEM_read_bio_PrivateKey(in, NULL, - ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - - if (pkey == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); - goto end; - } - ret = SSL_CTX_use_PrivateKey(ctx, pkey); - EVP_PKEY_free(pkey); -end: - if (in != NULL) - BIO_free(in); - return ret; -} - -int -ssl_ctx_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len) -{ - int ret; - BIO *in; - X509 *x; - X509 *ca; - unsigned long err; - - ret = 0; - x = ca = NULL; - - if ((in = BIO_new_mem_buf(buf, len)) == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); - goto end; - } - - if ((x = PEM_read_bio_X509(in, NULL, - ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata)) == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); - goto end; - } - - if (!SSL_CTX_use_certificate(ctx, x) || ERR_peek_error() != 0) - goto end; - - /* If we could set up our certificate, now proceed to - * the CA certificates. - */ - - if (ctx->extra_certs != NULL) { - sk_X509_pop_free(ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; - } - - while ((ca = PEM_read_bio_X509(in, NULL, - ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata)) != NULL) { - - if (!SSL_CTX_add_extra_chain_cert(ctx, ca)) - goto end; - } - - err = ERR_peek_last_error(); - if (ERR_GET_LIB(err) == ERR_LIB_PEM && - ERR_GET_REASON(err) == PEM_R_NO_START_LINE) - ERR_clear_error(); - else - goto end; - - ret = 1; -end: - if (ca != NULL) - X509_free(ca); - if (x != NULL) - X509_free(x); - if (in != NULL) - BIO_free(in); - return (ret); -} |