diff --git a/MANIFEST b/MANIFEST index 095f58472..70c9cbca2 100644 --- a/MANIFEST +++ b/MANIFEST @@ -358,6 +358,7 @@ logsrvd/regress/fuzz/fuzz_logsrvd_conf.c logsrvd/regress/fuzz/fuzz_logsrvd_conf.dict logsrvd/sendlog.c logsrvd/sendlog.h +logsrvd/tls_client.c logsrvd/tls_common.h logsrvd/tls_init.c m4/ax_append_flag.m4 diff --git a/logsrvd/Makefile.in b/logsrvd/Makefile.in index cd2f2e565..80ece85b1 100644 --- a/logsrvd/Makefile.in +++ b/logsrvd/Makefile.in @@ -122,7 +122,7 @@ PROGS = sudo_logsrvd sudo_sendlog LOGSRVD_OBJS = logsrv_util.o iolog_writer.o logsrvd.o logsrvd_conf.o \ tls_init.o -SENDLOG_OBJS = logsrv_util.o sendlog.o tls_init.o +SENDLOG_OBJS = logsrv_util.o sendlog.o tls_client.o tls_init.o IOBJS = $(LOGSRVD_OBJS:.o=.i) $(SENDLOG_OBJS:.o=.i) @@ -407,6 +407,24 @@ sendlog.i: $(srcdir)/sendlog.c $(incdir)/compat/getaddrinfo.h \ $(CC) -E -o $@ $(CPPFLAGS) $< sendlog.plog: sendlog.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/sendlog.c --i-file $< --output-file $@ +tls_client.o: $(srcdir)/tls_client.c $(incdir)/compat/stdbool.h \ + $(incdir)/hostcheck.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ + $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \ + $(srcdir)/tls_common.h $(top_builddir)/config.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/tls_client.c +tls_client.i: $(srcdir)/tls_client.c $(incdir)/compat/stdbool.h \ + $(incdir)/hostcheck.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ + $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \ + $(srcdir)/tls_common.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +tls_client.plog: tls_client.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/tls_client.c --i-file $< --output-file $@ tls_init.o: $(srcdir)/tls_init.c $(incdir)/compat/stdbool.h \ $(incdir)/hostcheck.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \ diff --git a/logsrvd/logsrv_util.h b/logsrvd/logsrv_util.h index 0668297df..c7479ba81 100644 --- a/logsrvd/logsrv_util.h +++ b/logsrvd/logsrv_util.h @@ -19,6 +19,8 @@ #ifndef SUDO_LOGSRV_UTIL_H #define SUDO_LOGSRV_UTIL_H +#include /* for INET_ADDRSTRLEN and INET6_ADDRSTRLEN */ + /* Default ports to listen on */ #define DEFAULT_PORT "30343" #define DEFAULT_PORT_TLS "30344" @@ -26,6 +28,15 @@ /* Maximum message size (2Mb) */ #define MESSAGE_SIZE_MAX (2 * 1024 * 1024) +struct peer_info { + const char *name; +#if defined(HAVE_STRUCT_IN6_ADDR) + char ipaddr[INET6_ADDRSTRLEN]; +#else + char ipaddr[INET_ADDRSTRLEN]; +#endif +}; + struct connection_buffer { TAILQ_ENTRY(connection_buffer) entries; uint8_t *data; diff --git a/logsrvd/sendlog.c b/logsrvd/sendlog.c index 40d76045b..3a3a4206a 100644 --- a/logsrvd/sendlog.c +++ b/logsrvd/sendlog.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2019-2020 Todd C. Miller + * Copyright (c) 2019-2021 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -80,12 +80,7 @@ TAILQ_HEAD(connection_list, client_closure); static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections); -static const char *server_name = "localhost"; -#if defined(HAVE_STRUCT_IN6_ADDR) -static char server_ip[INET6_ADDRSTRLEN]; -#else -static char server_ip[INET_ADDRSTRLEN]; -#endif +static struct peer_info server_info = { "localhost" }; static char *iolog_dir; static bool testrun = false; static int nr_of_conns = 1; @@ -165,7 +160,7 @@ help(void) * Returns open socket or -1 on error. */ static int -connect_server(const char *host, const char *port) +connect_server(struct peer_info *server, const char *port) { struct addrinfo hints, *res, *res0; const char *addr, *cause = "getaddrinfo"; @@ -175,9 +170,9 @@ connect_server(const char *host, const char *port) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(host, port, &hints, &res0); + error = getaddrinfo(server->name, port, &hints, &res0); if (error != 0) { - sudo_warnx(U_("unable to look up %s:%s: %s"), host, port, + sudo_warnx(U_("unable to look up %s:%s: %s"), server->name, port, gai_strerror(error)); debug_return_int(-1); } @@ -197,7 +192,7 @@ connect_server(const char *host, const char *port) sock = -1; continue; } - if (*server_ip == '\0') { + if (server->ipaddr[0] == '\0') { switch (res->ai_family) { case AF_INET: addr = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr; @@ -213,8 +208,8 @@ connect_server(const char *host, const char *port) sock = -1; continue; } - if (inet_ntop(res->ai_family, addr, server_ip, - sizeof(server_ip)) == NULL) { + if (inet_ntop(res->ai_family, addr, server->ipaddr, + sizeof(server->ipaddr)) == NULL) { sudo_warnx("%s", U_("unable to get server IP addr")); } } @@ -377,6 +372,18 @@ fmt_client_hello(struct client_closure *closure) debug_return_bool(ret); } +#if defined(HAVE_OPENSSL) +/* Wrapper for fmt_client_hello() called via tls_connect_cb() */ +static bool +tls_start_fn(struct tls_client_closure *tls_client) +{ + struct client_closure *closure = + __containerof(tls_client, struct client_closure, tls_client); + + return fmt_client_hello(closure); +} +#endif /* HAVE_OPENSSL */ + static void free_info_messages(InfoMessage **info_msgs, size_t n_info_msgs) { @@ -1115,13 +1122,14 @@ server_msg_cb(int fd, int what, void *v) #if defined(HAVE_OPENSSL) if (cert != NULL) { + SSL *ssl = closure->tls_client.ssl; sudo_debug_printf(SUDO_DEBUG_INFO, "%s: reading ServerMessage (TLS)", __func__); - nread = SSL_read(closure->ssl, buf->data + buf->len, buf->size - buf->len); + nread = SSL_read(ssl, buf->data + buf->len, buf->size - buf->len); if (nread <= 0) { const char *errstr; int err; - switch (SSL_get_error(closure->ssl, nread)) { + switch (SSL_get_error(ssl, nread)) { case SSL_ERROR_ZERO_RETURN: /* ssl connection shutdown cleanly */ nread = 0; @@ -1260,11 +1268,12 @@ client_msg_cb(int fd, int what, void *v) #if defined(HAVE_OPENSSL) if (cert != NULL) { - nwritten = SSL_write(closure->ssl, buf->data + buf->off, buf->len - buf->off); + SSL *ssl = closure->tls_client.ssl; + nwritten = SSL_write(ssl, buf->data + buf->off, buf->len - buf->off); if (nwritten <= 0) { const char *errstr; - switch (SSL_get_error(closure->ssl, nwritten)) { + switch (SSL_get_error(ssl, nwritten)) { case SSL_ERROR_ZERO_RETURN: /* ssl connection shutdown */ goto bad; @@ -1351,166 +1360,6 @@ parse_timespec(struct timespec *ts, char *strval) debug_return_bool(true); } -#if defined(HAVE_OPENSSL) -/* - * Check that the server's certificate is valid that it contains the - * server name or IP address. - * Returns 0 if the cert is invalid, else 1. - */ -static int -verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx) -{ - X509 *current_cert; - X509 *peer_cert; - debug_decl(verify_peer_identity, SUDO_DEBUG_UTIL); - - /* if pre-verification of the cert failed, just propagate that result back */ - if (preverify_ok != 1) { - debug_return_int(0); - } - - /* since this callback is called for each cert in the chain, - * check that current cert is the peer's certificate - */ - current_cert = X509_STORE_CTX_get_current_cert(ctx); - peer_cert = X509_STORE_CTX_get0_cert(ctx); - if (current_cert != peer_cert) { - debug_return_int(1); - } - - if (validate_hostname(peer_cert, server_name, server_ip, 0) == MatchFound) { - debug_return_int(1); - } - - debug_return_int(0); -} - -static void -tls_connect_cb(int sock, int what, void *v) -{ - struct client_closure *closure = v; - struct sudo_event_base *evbase = closure->evbase; - struct timespec timeo = { TLS_HANDSHAKE_TIMEO_SEC, 0 }; - const char *errstr; - int con_stat; - debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL); - - if (what == SUDO_EV_TIMEOUT) { - sudo_warnx("%s", U_("TLS handshake timeout occurred")); - goto bad; - } - - con_stat = SSL_connect(closure->ssl); - - if (con_stat == 1) { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "SSL_connect successful"); - closure->tls_connect_state = true; - } else { - switch (SSL_get_error(closure->ssl, con_stat)) { - /* TLS handshake is not finished, reschedule event */ - case SSL_ERROR_WANT_READ: - sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO, - "SSL_connect returns SSL_ERROR_WANT_READ"); - if (what != SUDO_EV_READ) { - if (sudo_ev_set(closure->tls_connect_ev, closure->sock, - SUDO_EV_READ, tls_connect_cb, closure) == -1) { - sudo_warnx("%s", U_("unable to set event")); - goto bad; - } - } - if (sudo_ev_add(evbase, closure->tls_connect_ev, &timeo, false) == -1) { - sudo_warnx("%s", U_("unable to add event to queue")); - goto bad; - } - break; - case SSL_ERROR_WANT_WRITE: - sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO, - "SSL_connect returns SSL_ERROR_WANT_WRITE"); - if (what != SUDO_EV_WRITE) { - if (sudo_ev_set(closure->tls_connect_ev, closure->sock, - SUDO_EV_WRITE, tls_connect_cb, closure) == -1) { - sudo_warnx("%s", U_("unable to set event")); - goto bad; - } - } - if (sudo_ev_add(evbase, closure->tls_connect_ev, &timeo, false) == -1) { - sudo_warnx("%s", U_("unable to add event to queue")); - goto bad; - } - break; - case SSL_ERROR_SYSCALL: - sudo_warnx(U_("TLS connection failed: %s"), strerror(errno)); - goto bad; - default: - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("TLS connection failed: %s"), errstr); - goto bad; - } - } - - if (closure->tls_connect_state) { - if (!testrun) { - printf("Negotiated protocol version: %s\n", SSL_get_version(closure->ssl)); - printf("Negotiated ciphersuite: %s\n", SSL_get_cipher(closure->ssl)); - } - - /* Done with TLS connect, send ClientHello */ - sudo_ev_free(closure->tls_connect_ev); - closure->tls_connect_ev = NULL; - if (!fmt_client_hello(closure)) - goto bad; - } - - debug_return; - -bad: - sudo_ev_loopbreak(evbase); - debug_return; -} - -static bool -tls_setup(struct client_closure *closure) -{ - const char *errstr; - debug_decl(tls_setup, SUDO_DEBUG_UTIL); - - ssl_ctx = init_tls_context(ca_bundle, cert, key, NULL, NULL, NULL, false); - if (ssl_ctx == NULL) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("Unable to initialize ssl context: %s"), errstr); - goto bad; - } - - if (verify_server) { - /* verify server cert during the handshake */ - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_peer_identity); - } - - if ((closure->ssl = SSL_new(ssl_ctx)) == NULL) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("Unable to allocate ssl object: %s"), errstr); - goto bad; - } - if (SSL_set_fd(closure->ssl, closure->sock) <= 0) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("Unable to attach socket to the ssl object: %s"), - errstr); - goto bad; - } - - if (sudo_ev_add(closure->evbase, closure->tls_connect_ev, NULL, false) == -1) { - sudo_warnx("%s", U_("unable to add event to queue")); - goto bad; - } - - debug_return_bool(true); - -bad: - debug_return_bool(false); -} -#endif /* HAVE_OPENSSL */ - /* * Free client closure contents. */ @@ -1522,11 +1371,11 @@ client_closure_free(struct client_closure *closure) if (closure != NULL) { TAILQ_REMOVE(&connections, closure, entries); #if defined(HAVE_OPENSSL) - if (closure->ssl != NULL) { - SSL_shutdown(closure->ssl); - SSL_free(closure->ssl); + if (closure->tls_client.ssl != NULL) { + SSL_shutdown(closure->tls_client.ssl); + SSL_free(closure->tls_client.ssl); } - sudo_ev_free(closure->tls_connect_ev); + sudo_ev_free(closure->tls_client.tls_connect_ev); #endif sudo_ev_free(closure->read_ev); sudo_ev_free(closure->write_ev); @@ -1588,10 +1437,13 @@ client_closure_alloc(int sock, struct sudo_event_base *base, #if defined(HAVE_OPENSSL) if (cert != NULL) { - closure->tls_connect_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE, - tls_connect_cb, closure); - if (closure->tls_connect_ev == NULL) + closure->tls_client.tls_connect_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE, + tls_connect_cb, &closure->tls_client); + if (closure->tls_client.tls_connect_ev == NULL) goto bad; + closure->tls_client.evbase = base; + closure->tls_client.peer_name = &server_info; + closure->tls_client.start_fn = tls_start_fn; } #endif @@ -1673,7 +1525,7 @@ main(int argc, char *argv[]) accept_only = true; break; case 'h': - server_name = optarg; + server_info.name = optarg; break; case 'i': iolog_id = optarg; @@ -1766,12 +1618,12 @@ main(int argc, char *argv[]) printf("connecting clients...\n"); for (int i = 0; i < nr_of_conns; i++) { - sock = connect_server(server_name, port); + sock = connect_server(&server_info, port); if (sock == -1) goto bad; if (!testrun) - printf("Connected to %s:%s\n", server_name, port); + printf("Connected to %s:%s\n", server_info.name, port); closure = client_closure_alloc(sock, evbase, &elapsed, &restart, iolog_id, reject_reason, accept_only, evlog); @@ -1789,7 +1641,8 @@ main(int argc, char *argv[]) #if defined(HAVE_OPENSSL) if (cert != NULL) { - if (!tls_setup(closure)) + if (!tls_client_setup(closure->sock, ca_bundle, cert, key, NULL, + NULL, NULL, verify_server, false, &closure->tls_client)) goto bad; } else #endif diff --git a/logsrvd/sendlog.h b/logsrvd/sendlog.h index 1c17f216d..a4dd1d8d8 100644 --- a/logsrvd/sendlog.h +++ b/logsrvd/sendlog.h @@ -59,9 +59,7 @@ struct client_closure { struct connection_buffer read_buf; struct connection_buffer write_buf; #if defined(HAVE_OPENSSL) - SSL *ssl; - struct sudo_event *tls_connect_ev; - bool tls_connect_state; + struct tls_client_closure tls_client; #endif struct sudo_event *read_ev; struct sudo_event *write_ev; diff --git a/logsrvd/tls_client.c b/logsrvd/tls_client.c new file mode 100644 index 000000000..fbedad395 --- /dev/null +++ b/logsrvd/tls_client.c @@ -0,0 +1,250 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019-2021 Todd C. Miller + * + * 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 +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#endif +#include +#include +#include + +#if defined(HAVE_OPENSSL) +# include +# include +#endif + +#include "sudo_compat.h" +#include "sudo_debug.h" +#include "sudo_event.h" +#include "sudo_fatal.h" +#include "sudo_gettext.h" +#include "sudo_util.h" + +#include "hostcheck.h" +#include "logsrv_util.h" +#include "tls_common.h" + +#define TLS_HANDSHAKE_TIMEO_SEC 10 + +#if defined(HAVE_OPENSSL) + +/* + * Check that the server's certificate is valid that it contains the + * server name or IP address. + * Returns 0 if the cert is invalid, else 1. + */ +static int +verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx) +{ + HostnameValidationResult result; + struct peer_info *peer_info; + SSL *ssl; + X509 *current_cert; + X509 *peer_cert; + debug_decl(verify_peer_identity, SUDO_DEBUG_UTIL); + + /* if pre-verification of the cert failed, just propagate that result back */ + if (preverify_ok != 1) { + debug_return_int(0); + } + + /* + * Since this callback is called for each cert in the chain, + * check that current cert is the peer's certificate + */ + current_cert = X509_STORE_CTX_get_current_cert(ctx); + peer_cert = X509_STORE_CTX_get0_cert(ctx); + if (current_cert != peer_cert) { + debug_return_int(1); + } + + /* Fetch the attached peer_info from the ssl connection object. */ + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + peer_info = SSL_get_ex_data(ssl, 1); + + /* + * Validate the cert based on the host name and IP address. + * If host name is not known, validate_hostname() can resolve it. + */ + result = validate_hostname(peer_cert, + peer_info->name ? peer_info->name : peer_info->ipaddr, + peer_info->ipaddr, peer_info->name ? 0 : 1); + + debug_return_int(result == MatchFound); +} + +void +tls_connect_cb(int sock, int what, void *v) +{ + struct tls_client_closure *tls_client = v; + struct sudo_event_base *evbase = tls_client->evbase; + struct timespec timeo = { TLS_HANDSHAKE_TIMEO_SEC, 0 }; + const char *errstr; + int con_stat; + debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL); + + if (what == SUDO_EV_TIMEOUT) { + sudo_warnx("%s", U_("TLS handshake timeout occurred")); + goto bad; + } + + con_stat = SSL_connect(tls_client->ssl); + + if (con_stat == 1) { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "SSL_connect successful"); + tls_client->tls_connect_state = true; + } else { + switch (SSL_get_error(tls_client->ssl, con_stat)) { + /* TLS handshake is not finished, reschedule event */ + case SSL_ERROR_WANT_READ: + sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO, + "SSL_connect returns SSL_ERROR_WANT_READ"); + if (what != SUDO_EV_READ) { + if (sudo_ev_set(tls_client->tls_connect_ev, + SSL_get_fd(tls_client->ssl), SUDO_EV_READ, + tls_connect_cb, tls_client) == -1) { + sudo_warnx("%s", U_("unable to set event")); + goto bad; + } + } + if (sudo_ev_add(evbase, tls_client->tls_connect_ev, &timeo, false) == -1) { + sudo_warnx("%s", U_("unable to add event to queue")); + goto bad; + } + break; + case SSL_ERROR_WANT_WRITE: + sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO, + "SSL_connect returns SSL_ERROR_WANT_WRITE"); + if (what != SUDO_EV_WRITE) { + if (sudo_ev_set(tls_client->tls_connect_ev, + SSL_get_fd(tls_client->ssl), SUDO_EV_WRITE, + tls_connect_cb, tls_client) == -1) { + sudo_warnx("%s", U_("unable to set event")); + goto bad; + } + } + if (sudo_ev_add(evbase, tls_client->tls_connect_ev, &timeo, false) == -1) { + sudo_warnx("%s", U_("unable to add event to queue")); + goto bad; + } + break; + case SSL_ERROR_SYSCALL: + sudo_warnx(U_("TLS connection failed: %s"), strerror(errno)); + goto bad; + default: + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("TLS connection failed: %s"), errstr); + goto bad; + } + } + + if (tls_client->tls_connect_state) { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "TLS version: %s, negotiated cipher suite: %s", + SSL_get_version(tls_client->ssl), SSL_get_cipher(tls_client->ssl)); + + /* Done with TLS connect, send ClientHello */ + sudo_ev_free(tls_client->tls_connect_ev); + tls_client->tls_connect_ev = NULL; + if (!tls_client->start_fn(tls_client)) + goto bad; + } + + debug_return; + +bad: + sudo_ev_loopbreak(evbase); + debug_return; +} + +bool +tls_ctx_client_setup(SSL_CTX *ssl_ctx, int sock, + struct tls_client_closure *closure) +{ + const char *errstr; + bool ret = false; + debug_decl(tls_ctx_client_setup, SUDO_DEBUG_UTIL); + + if ((closure->ssl = SSL_new(ssl_ctx)) == NULL) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to allocate ssl object: %s"), errstr); + goto done; + } + + if (SSL_set_ex_data(closure->ssl, 1, closure->peer_name) <= 0) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("Unable to attach user data to the ssl object: %s"), + errstr); + goto done; + } + + if (SSL_set_fd(closure->ssl, sock) <= 0) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("Unable to attach socket to the ssl object: %s"), + errstr); + goto done; + } + + if (sudo_ev_add(closure->evbase, closure->tls_connect_ev, NULL, false) == -1) { + sudo_warnx("%s", U_("unable to add event to queue")); + goto done; + } + + ret = true; + +done: + debug_return_bool(ret); +} + +bool +tls_client_setup(int sock, const char *ca_bundle_file, const char *cert_file, + const char *key_file, const char *dhparam_file, const char *ciphers_v12, + const char *ciphers_v13, bool verify_server, bool check_peer, + struct tls_client_closure *closure) +{ + SSL_CTX *ssl_ctx; + debug_decl(tls_client_setup, SUDO_DEBUG_UTIL); + + ssl_ctx = init_tls_context(ca_bundle_file, cert_file, key_file, + dhparam_file, ciphers_v12,ciphers_v13, verify_server); + if (ssl_ctx == NULL) { + sudo_warnx(U_("unable to initialize TLS context")); + debug_return_bool(false); + } + + if (check_peer) { + /* Verify server cert during the handshake. */ + SSL_CTX_set_verify(ssl_ctx, + SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_peer_identity); + } + + debug_return_bool(tls_ctx_client_setup(ssl_ctx, sock, closure)); +} +#endif /* HAVE_OPENSSL */ diff --git a/logsrvd/tls_common.h b/logsrvd/tls_common.h index 5adb0dcad..c84e441e1 100644 --- a/logsrvd/tls_common.h +++ b/logsrvd/tls_common.h @@ -24,6 +24,20 @@ #if defined(HAVE_OPENSSL) # include +struct tls_client_closure { + SSL *ssl; + struct sudo_event_base *evbase; /* duplicated */ + struct sudo_event *tls_connect_ev; + struct peer_info *peer_name; + bool (*start_fn)(struct tls_client_closure *); + bool tls_connect_state; +}; + +/* tls_client.c */ +void tls_connect_cb(int sock, int what, void *v); +bool tls_client_setup(int sock, const char *ca_bundle_file, const char *cert_file, const char *key_file, const char *dhparam_file, const char *ciphers_v12, const char *ciphers_v13, bool verify_server, bool check_peer, struct tls_client_closure *closure); +bool tls_ctx_client_setup(SSL_CTX *ssl_ctx, int sock, struct tls_client_closure *closure); + /* tls_init.c */ SSL_CTX *init_tls_context(const char *ca_bundle_file, const char *cert_file, const char *key_file, const char *dhparam_file, const char *ciphers_v12, const char *ciphers_v13, bool verify_cert);