From 71e5275a1c1fa89f0c9254f3d49aa9dc6c1a609e Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 10 Mar 2021 16:29:27 -0700 Subject: [PATCH] Move common TLS initialization code to tls_init.c. --- MANIFEST | 2 + logsrvd/Makefile.in | 45 +++++-- logsrvd/logsrvd.c | 272 ++------------------------------------ logsrvd/logsrvd.h | 1 + logsrvd/sendlog.c | 84 ++---------- logsrvd/sendlog.h | 1 + logsrvd/tls_common.h | 32 +++++ logsrvd/tls_init.c | 307 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 394 insertions(+), 350 deletions(-) create mode 100644 logsrvd/tls_common.h create mode 100644 logsrvd/tls_init.c diff --git a/MANIFEST b/MANIFEST index 8e7a9e78b..095f58472 100644 --- a/MANIFEST +++ b/MANIFEST @@ -358,6 +358,8 @@ logsrvd/regress/fuzz/fuzz_logsrvd_conf.c logsrvd/regress/fuzz/fuzz_logsrvd_conf.dict logsrvd/sendlog.c logsrvd/sendlog.h +logsrvd/tls_common.h +logsrvd/tls_init.c m4/ax_append_flag.m4 m4/ax_check_compile_flag.m4 m4/ax_check_link_flag.m4 diff --git a/logsrvd/Makefile.in b/logsrvd/Makefile.in index f8364580a..cd2f2e565 100644 --- a/logsrvd/Makefile.in +++ b/logsrvd/Makefile.in @@ -119,9 +119,10 @@ SHELL = @SHELL@ PROGS = sudo_logsrvd sudo_sendlog -LOGSRVD_OBJS = logsrv_util.o iolog_writer.o logsrvd.o logsrvd_conf.o +LOGSRVD_OBJS = logsrv_util.o iolog_writer.o logsrvd.o logsrvd_conf.o \ + tls_init.o -SENDLOG_OBJS = logsrv_util.o sendlog.o +SENDLOG_OBJS = logsrv_util.o sendlog.o tls_init.o IOBJS = $(LOGSRVD_OBJS:.o=.i) $(SENDLOG_OBJS:.o=.i) @@ -283,7 +284,7 @@ fuzz_logsrvd_conf.o: $(srcdir)/regress/fuzz/fuzz_logsrvd_conf.c \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ - $(top_builddir)/config.h + $(srcdir)/tls_common.h $(top_builddir)/config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/fuzz/fuzz_logsrvd_conf.c fuzz_logsrvd_conf.i: $(srcdir)/regress/fuzz/fuzz_logsrvd_conf.c \ $(incdir)/compat/stdbool.h $(incdir)/log_server.pb-c.h \ @@ -292,7 +293,7 @@ fuzz_logsrvd_conf.i: $(srcdir)/regress/fuzz/fuzz_logsrvd_conf.c \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ - $(top_builddir)/config.h + $(srcdir)/tls_common.h $(top_builddir)/config.h $(CC) -E -o $@ $(CPPFLAGS) $< fuzz_logsrvd_conf.plog: fuzz_logsrvd_conf.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/fuzz/fuzz_logsrvd_conf.c --i-file $< --output-file $@ @@ -302,7 +303,8 @@ iolog_writer.o: $(srcdir)/iolog_writer.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \ - $(srcdir)/logsrvd.h $(top_builddir)/config.h + $(srcdir)/logsrvd.h $(srcdir)/tls_common.h \ + $(top_builddir)/config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_writer.c iolog_writer.i: $(srcdir)/iolog_writer.c $(incdir)/compat/stdbool.h \ $(incdir)/log_server.pb-c.h $(incdir)/protobuf-c/protobuf-c.h \ @@ -310,7 +312,8 @@ iolog_writer.i: $(srcdir)/iolog_writer.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \ - $(srcdir)/logsrvd.h $(top_builddir)/config.h + $(srcdir)/logsrvd.h $(srcdir)/tls_common.h \ + $(top_builddir)/config.h $(CC) -E -o $@ $(CPPFLAGS) $< iolog_writer.plog: iolog_writer.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_writer.c --i-file $< --output-file $@ @@ -339,7 +342,7 @@ logsrvd.o: $(srcdir)/logsrvd.c $(incdir)/compat/getopt.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_json.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_rand.h $(incdir)/sudo_util.h \ - $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ + $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h $(srcdir)/tls_common.h \ $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logsrvd.c logsrvd.i: $(srcdir)/logsrvd.c $(incdir)/compat/getopt.h \ @@ -351,7 +354,7 @@ logsrvd.i: $(srcdir)/logsrvd.c $(incdir)/compat/getopt.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_json.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_rand.h $(incdir)/sudo_util.h \ - $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ + $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h $(srcdir)/tls_common.h \ $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -E -o $@ $(CPPFLAGS) $< logsrvd.plog: logsrvd.i @@ -364,7 +367,8 @@ logsrvd_conf.o: $(srcdir)/logsrvd_conf.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ - $(top_builddir)/config.h $(top_builddir)/pathnames.h + $(srcdir)/tls_common.h $(top_builddir)/config.h \ + $(top_builddir)/pathnames.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logsrvd_conf.c logsrvd_conf.i: $(srcdir)/logsrvd_conf.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/compat/stdbool.h $(incdir)/log_server.pb-c.h \ @@ -374,7 +378,8 @@ logsrvd_conf.i: $(srcdir)/logsrvd_conf.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(srcdir)/logsrv_util.h $(srcdir)/logsrvd.h \ - $(top_builddir)/config.h $(top_builddir)/pathnames.h + $(srcdir)/tls_common.h $(top_builddir)/config.h \ + $(top_builddir)/pathnames.h $(CC) -E -o $@ $(CPPFLAGS) $< logsrvd_conf.plog: logsrvd_conf.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logsrvd_conf.c --i-file $< --output-file $@ @@ -387,7 +392,7 @@ sendlog.o: $(srcdir)/sendlog.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h $(srcdir)/sendlog.h \ - $(top_builddir)/config.h + $(srcdir)/tls_common.h $(top_builddir)/config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sendlog.c sendlog.i: $(srcdir)/sendlog.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/compat/getopt.h $(incdir)/compat/stdbool.h \ @@ -398,7 +403,23 @@ sendlog.i: $(srcdir)/sendlog.c $(incdir)/compat/getaddrinfo.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/logsrv_util.h $(srcdir)/sendlog.h \ - $(top_builddir)/config.h + $(srcdir)/tls_common.h $(top_builddir)/config.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_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 \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ + $(srcdir)/tls_common.h $(top_builddir)/config.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/tls_init.c +tls_init.i: $(srcdir)/tls_init.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 \ + $(srcdir)/tls_common.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +tls_init.plog: tls_init.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/tls_init.c --i-file $< --output-file $@ diff --git a/logsrvd/logsrvd.c b/logsrvd/logsrvd.c index cfb6398ec..3fca422d4 100644 --- a/logsrvd/logsrvd.c +++ b/logsrvd/logsrvd.c @@ -74,11 +74,6 @@ #include "hostcheck.h" #include "logsrvd.h" -#if defined(HAVE_OPENSSL) -# define LOGSRVD_DEFAULT_CIPHER_LST12 "HIGH:!aNULL" -# define LOGSRVD_DEFAULT_CIPHER_LST13 "TLS_AES_256_GCM_SHA384" -#endif - #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 #endif @@ -1173,131 +1168,6 @@ verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx) } } -static bool -verify_server_cert(SSL_CTX *ctx, const struct logsrvd_tls_config *tls_config) -{ -#ifdef HAVE_SSL_CTX_GET0_CERTIFICATE - bool ret = false; - X509_STORE_CTX *store_ctx = NULL; - X509_STORE *ca_store; - STACK_OF(X509) *chain_certs; - X509 *x509; - debug_decl(verify_server_cert, SUDO_DEBUG_UTIL); - - if ((x509 = SSL_CTX_get0_certificate(ctx)) == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to get X509 object from SSL_CTX: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto exit; - } - - if ((store_ctx = X509_STORE_CTX_new()) == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to allocate X509_STORE_CTX object: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto exit; - } - - if (!SSL_CTX_get0_chain_certs(ctx, &chain_certs)) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to get chain certs: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto exit; - } - - if ((ca_store = SSL_CTX_get_cert_store(ctx)) != NULL) - X509_STORE_set_flags(ca_store, X509_V_FLAG_X509_STRICT); - - if (!X509_STORE_CTX_init(store_ctx, ca_store, x509, chain_certs)) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to initialize X509_STORE_CTX object: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto exit; - } - - if (X509_verify_cert(store_ctx) <= 0) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to verify cert %s: %s", tls_config->cert_path, - ERR_error_string(ERR_get_error(), NULL)); - goto exit; - } - - ret = true; -exit: - X509_STORE_CTX_free(store_ctx); - - debug_return_bool(ret); -#else - /* TODO: verify server cert with old OpenSSL */ - return true; -#endif /* HAVE_SSL_CTX_GET0_CERTIFICATE */ -} - -static bool -init_tls_ciphersuites(SSL_CTX *ctx, const struct logsrvd_tls_config *tls_config) -{ - const char *errstr; - int success = 0; - debug_decl(init_tls_ciphersuites, SUDO_DEBUG_UTIL); - - if (tls_config->ciphers_v12) { - /* try to set TLS v1.2 ciphersuite list from config if given */ - success = SSL_CTX_set_cipher_list(ctx, tls_config->ciphers_v12); - if (success) { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "TLS 1.2 ciphersuite list set to %s", tls_config->ciphers_v12); - } else { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"), - tls_config->ciphers_v12, errstr); - } - } - if (!success) { - /* fallback to default ciphersuites for TLS v1.2 */ - if (SSL_CTX_set_cipher_list(ctx, LOGSRVD_DEFAULT_CIPHER_LST12) <= 0) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"), - LOGSRVD_DEFAULT_CIPHER_LST12, errstr); - debug_return_bool(false); - } else { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "TLS v1.2 ciphersuite list set to %s (default)", - LOGSRVD_DEFAULT_CIPHER_LST12); - } - } - -# if defined(HAVE_SSL_CTX_SET_CIPHERSUITES) - success = 0; - if (tls_config->ciphers_v13) { - /* try to set TLSv1.3 ciphersuite list from config */ - success = SSL_CTX_set_ciphersuites(ctx, tls_config->ciphers_v13); - if (success) { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "TLS v1.3 ciphersuite list set to %s", tls_config->ciphers_v13); - } else { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"), - tls_config->ciphers_v13, errstr); - } - } - if (!success) { - /* fallback to default ciphersuites for TLS v1.3 */ - if (SSL_CTX_set_ciphersuites(ctx, LOGSRVD_DEFAULT_CIPHER_LST13) <= 0) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"), - LOGSRVD_DEFAULT_CIPHER_LST13, errstr); - debug_return_bool(false); - } else { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "TLS v1.3 ciphersuite list set to %s (default)", - LOGSRVD_DEFAULT_CIPHER_LST13); - } - } -# endif - - debug_return_bool(true); -} - /* * Calls series of openssl initialization functions in order to * be able to establish configured network connections over TLS @@ -1305,146 +1175,24 @@ init_tls_ciphersuites(SSL_CTX *ctx, const struct logsrvd_tls_config *tls_config) static bool init_tls_server_context(void) { - const SSL_METHOD *method; - FILE *dhparam_file = NULL; - SSL_CTX *ctx = NULL; struct logsrvd_tls_runtime *tls_runtime = logsrvd_get_tls_runtime(); const struct logsrvd_tls_config *tls_config = logsrvd_get_tls_config(); - bool ca_bundle_required = tls_config->verify | tls_config->check_peer; - const char *errstr; debug_decl(init_tls_server_context, SUDO_DEBUG_UTIL); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - SSL_load_error_strings(); + tls_runtime->ssl_ctx = init_tls_context(tls_config->cacert_path, + tls_config->cert_path, tls_config->pkey_path, tls_config->dhparams_path, + tls_config->ciphers_v12, tls_config->ciphers_v13, tls_config->verify); - if ((method = TLS_server_method()) == NULL) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to get TLS server method: %s"), errstr); - goto bad; - } - if ((ctx = SSL_CTX_new(method)) == NULL) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to create TLS context: %s"), errstr); - goto bad; - } - - if (SSL_CTX_use_certificate_chain_file(ctx, tls_config->cert_path) <= 0) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("%s: %s"), tls_config->cert_path, errstr); - sudo_warnx(U_("unable to load certificate %s"), tls_config->cert_path); - goto bad; - } - - /* if server or client authentication is required, CA bundle file has to be prepared */ - if (ca_bundle_required) { - if (tls_config->cacert_path != NULL) { - STACK_OF(X509_NAME) *cacerts = - SSL_load_client_CA_file(tls_config->cacert_path); - - if (cacerts == NULL) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("%s: %s"), tls_config->cacert_path, errstr); - sudo_warnx(U_("unable to load certificate authority bundle %s"), - tls_config->cacert_path); - goto bad; - } - SSL_CTX_set_client_CA_list(ctx, cacerts); - - /* set the location of the CA bundle file for verification */ - if (SSL_CTX_load_verify_locations(ctx, tls_config->cacert_path, NULL) <= 0) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx("SSL_CTX_load_verify_locations: %s", errstr); - goto bad; - } - } else { - if (!SSL_CTX_set_default_verify_paths(ctx)) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx("SSL_CTX_set_default_verify_paths: %s", errstr); - goto bad; - } + if (tls_runtime->ssl_ctx != NULL) { + if (tls_config->check_peer) { + /* Verify server cert during the handshake. */ + SSL_CTX_set_verify(tls_runtime->ssl_ctx, + SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_peer_identity); } - - /* only verify server cert if it is set in the configuration */ - if (tls_config->verify) { - if (!verify_server_cert(ctx, tls_config)) - goto bad; - } else { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "skipping server cert check"); - } + debug_return_bool(true); } - /* if peer authentication is enabled, verify client cert during TLS handshake - * The last parameter is a callback, where identity validation (hostname/ip) - * will be performed, because it is not automatically done by openssl. - */ - if (tls_config->check_peer) { - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_peer_identity); - } - - /* if private key file was not set, assume that the cert file contains the private key */ - char* pkey = (tls_config->pkey_path == NULL ? tls_config->cert_path : tls_config->pkey_path); - - if (!SSL_CTX_use_PrivateKey_file(ctx, pkey, SSL_FILETYPE_PEM) || - !SSL_CTX_check_private_key(ctx)) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("%s: %s"), pkey, errstr); - sudo_warnx(U_("unable to load private key %s"), pkey); - goto bad; - } - - /* initialize TLSv1.2 and TLSv1.3 ciphersuites */ - if (!init_tls_ciphersuites(ctx, tls_config)) { - goto bad; - } - - /* try to load and set diffie-hellman parameters */ - if (tls_config->dhparams_path != NULL) - dhparam_file = fopen(tls_config->dhparams_path, "r"); - if (dhparam_file != NULL) { - DH *dhparams = PEM_read_DHparams(dhparam_file, NULL, NULL, NULL); - if (dhparams != NULL) { - if (!SSL_CTX_set_tmp_dh(ctx, dhparams)) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set diffie-hellman parameters: %s"), - errstr); - DH_free(dhparams); - } else { - sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, - "diffie-hellman parameters are loaded"); - } - } else { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set diffie-hellman parameters: %s"), - errstr); - } - fclose(dhparam_file); - } else { - sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, - "dhparam file not found, will use default parameters"); - } - - /* audit server supports TLS version 1.2 or higher */ -#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION - if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) { - errstr = ERR_reason_error_string(ERR_get_error()); - sudo_warnx(U_("unable to set minimum protocol version to TLS 1.2: %s"), - errstr); - goto bad; - } -#else - SSL_CTX_set_options(ctx, - SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1); -#endif - - tls_runtime->ssl_ctx = ctx; - - debug_return_bool(true); - -bad: - SSL_CTX_free(ctx); - debug_return_bool(false); } diff --git a/logsrvd/logsrvd.h b/logsrvd/logsrvd.h index 5e99f60c2..bdc8c4580 100644 --- a/logsrvd/logsrvd.h +++ b/logsrvd/logsrvd.h @@ -30,6 +30,7 @@ #endif #include "logsrv_util.h" +#include "tls_common.h" /* Default timeout value for server socket */ #define DEFAULT_SOCKET_TIMEOUT_SEC 30 diff --git a/logsrvd/sendlog.c b/logsrvd/sendlog.c index 60e34d12d..40d76045b 100644 --- a/logsrvd/sendlog.c +++ b/logsrvd/sendlog.c @@ -1385,81 +1385,6 @@ verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx) debug_return_int(0); } -static SSL_CTX * -init_tls_client_context(const char *ca_bundle_file, const char *cert_file, const char *key_file) -{ - const SSL_METHOD *method; - SSL_CTX *ctx = NULL; - debug_decl(init_tls_client_context, SUDO_DEBUG_UTIL); - - SSL_library_init(); - OpenSSL_add_all_algorithms(); - SSL_load_error_strings(); - - if ((method = TLS_client_method()) == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "creation of SSL_METHOD failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } - if ((ctx = SSL_CTX_new(method)) == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "creation of new SSL_CTX object failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } -#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION - if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to restrict min. protocol version: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } -#else - SSL_CTX_set_options(ctx, - SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1); -#endif - - if (cert_file) { - if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to load cert to the ssl context: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } - if (!SSL_CTX_use_PrivateKey_file(ctx, key_file, X509_FILETYPE_PEM)) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to load key to the ssl context: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } - } - - if (ca_bundle_file != NULL) { - /* sets the location of the CA bundle file for verification purposes */ - if (SSL_CTX_load_verify_locations(ctx, ca_bundle_file, NULL) <= 0) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "calling SSL_CTX_load_verify_locations() failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto bad; - } - } - - if (verify_server) { - /* verify server cert during the handshake */ - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_identity); - } - - goto done; - -bad: - SSL_CTX_free(ctx); - ctx = NULL; - -done: - debug_return_ptr(ctx); -} - static void tls_connect_cb(int sock, int what, void *v) { @@ -1550,11 +1475,18 @@ tls_setup(struct client_closure *closure) const char *errstr; debug_decl(tls_setup, SUDO_DEBUG_UTIL); - if ((ssl_ctx = init_tls_client_context(ca_bundle, cert, key)) == NULL) { + 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); diff --git a/logsrvd/sendlog.h b/logsrvd/sendlog.h index 0262cbb87..1c17f216d 100644 --- a/logsrvd/sendlog.h +++ b/logsrvd/sendlog.h @@ -30,6 +30,7 @@ #endif #include "logsrv_util.h" +#include "tls_common.h" enum client_state { ERROR, diff --git a/logsrvd/tls_common.h b/logsrvd/tls_common.h new file mode 100644 index 000000000..5adb0dcad --- /dev/null +++ b/logsrvd/tls_common.h @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 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. + */ + +#ifndef SUDO_TLS_COMMON_H +#define SUDO_TLS_COMMON_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +# include + +/* 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); + +#endif /* HAVE_OPENSSL */ + +#endif /* SUDO_TLS_COMMON_H */ diff --git a/logsrvd/tls_init.c b/logsrvd/tls_init.c new file mode 100644 index 000000000..efdc78144 --- /dev/null +++ b/logsrvd/tls_init.c @@ -0,0 +1,307 @@ +/* + * 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" + +#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 + +#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 "hostcheck.h" +#include "tls_common.h" + +#define DEFAULT_CIPHER_LST12 "HIGH:!aNULL" +#define DEFAULT_CIPHER_LST13 "TLS_AES_256_GCM_SHA384" + +#if defined(HAVE_OPENSSL) + +static bool +verify_cert_chain(SSL_CTX *ctx, const char *cert_file) +{ +#ifdef HAVE_SSL_CTX_GET0_CERTIFICATE + bool ret = false; + X509_STORE_CTX *store_ctx = NULL; + X509_STORE *ca_store; + STACK_OF(X509) *chain_certs; + X509 *x509; + debug_decl(verify_cert_chain, SUDO_DEBUG_UTIL); + + if ((x509 = SSL_CTX_get0_certificate(ctx)) == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to get X509 object from SSL_CTX: %s", + ERR_error_string(ERR_peek_error(), NULL)); + goto done; + } + + if ((store_ctx = X509_STORE_CTX_new()) == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to allocate X509_STORE_CTX object: %s", + ERR_error_string(ERR_peek_error(), NULL)); + goto done; + } + + if (!SSL_CTX_get0_chain_certs(ctx, &chain_certs)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to get chain certs: %s", + ERR_error_string(ERR_peek_error(), NULL)); + goto done; + } + + if ((ca_store = SSL_CTX_get_cert_store(ctx)) != NULL) + X509_STORE_set_flags(ca_store, X509_V_FLAG_X509_STRICT); + + if (!X509_STORE_CTX_init(store_ctx, ca_store, x509, chain_certs)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to initialize X509_STORE_CTX object: %s", + ERR_error_string(ERR_peek_error(), NULL)); + goto done; + } + + if (X509_verify_cert(store_ctx) <= 0) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to verify cert %s: %s", cert_file, + ERR_error_string(ERR_peek_error(), NULL)); + goto done; + } + + ret = true; +done: + X509_STORE_CTX_free(store_ctx); + + debug_return_bool(ret); +#else + /* TODO: verify server cert with old OpenSSL */ + return true; +#endif /* HAVE_SSL_CTX_GET0_CERTIFICATE */ +} + +static bool +init_tls_ciphersuites(SSL_CTX *ctx, const char *ciphers_v12, + const char *ciphers_v13) +{ + const char *errstr; + int success = 0; + debug_decl(init_tls_ciphersuites, SUDO_DEBUG_UTIL); + + if (ciphers_v12 != NULL) { + /* try to set TLS v1.2 ciphersuite list from config if given */ + success = SSL_CTX_set_cipher_list(ctx, ciphers_v12); + if (success) { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "TLS 1.2 ciphersuite list set to %s", ciphers_v12); + } else { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"), + ciphers_v12, errstr); + } + } + if (!success) { + /* fallback to default ciphersuites for TLS v1.2 */ + if (SSL_CTX_set_cipher_list(ctx, DEFAULT_CIPHER_LST12) <= 0) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"), + DEFAULT_CIPHER_LST12, errstr); + debug_return_bool(false); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "TLS v1.2 ciphersuite list set to %s (default)", + DEFAULT_CIPHER_LST12); + } + } + +# if defined(HAVE_SSL_CTX_SET_CIPHERSUITES) + success = 0; + if (ciphers_v13 != NULL) { + /* try to set TLSv1.3 ciphersuite list from config */ + success = SSL_CTX_set_ciphersuites(ctx, ciphers_v13); + if (success) { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "TLS v1.3 ciphersuite list set to %s", ciphers_v13); + } else { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"), + ciphers_v13, errstr); + } + } + if (!success) { + /* fallback to default ciphersuites for TLS v1.3 */ + if (SSL_CTX_set_ciphersuites(ctx, LOGSRVD_DEFAULT_CIPHER_LST13) <= 0) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"), + LOGSRVD_DEFAULT_CIPHER_LST13, errstr); + debug_return_bool(false); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "TLS v1.3 ciphersuite list set to %s (default)", + LOGSRVD_DEFAULT_CIPHER_LST13); + } + } +# endif + + debug_return_bool(true); +} + +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) +{ + SSL_CTX *ctx = NULL; + const char *errstr; + debug_decl(init_tls_context, SUDO_DEBUG_UTIL); + + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + + /* Create the ssl context and enforce TLS 1.2 or higher. */ + if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to create TLS context: %s"), errstr); + goto bad; + } +#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION + if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set minimum protocol version to TLS 1.2: %s"), + errstr); + goto bad; + } +#else + SSL_CTX_set_options(ctx, + SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1); +#endif + + if (ca_bundle_file != NULL) { + STACK_OF(X509_NAME) *cacerts = + SSL_load_client_CA_file(ca_bundle_file); + + if (cacerts == NULL) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("%s: %s"), ca_bundle_file, errstr); + goto bad; + } + SSL_CTX_set_client_CA_list(ctx, cacerts); + + if (SSL_CTX_load_verify_locations(ctx, ca_bundle_file, NULL) <= 0) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx("SSL_CTX_load_verify_locations: %s", errstr); + goto bad; + } + } else { + if (!SSL_CTX_set_default_verify_paths(ctx)) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx("SSL_CTX_set_default_verify_paths: %s", errstr); + goto bad; + } + } + + if (cert_file != NULL) { + if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("%s: %s"), cert_file, errstr); + goto bad; + } + if (key_file == NULL) { + /* No explicit key file set, try to use the cert file. */ + key_file = cert_file; + } + if (!SSL_CTX_use_PrivateKey_file(ctx, key_file, X509_FILETYPE_PEM) || + !SSL_CTX_check_private_key(ctx)) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("%s: %s"), key_file, errstr); + goto bad; + } + + /* Optionally verify the certificate we are using. */ + if (verify_cert) { + if (!verify_cert_chain(ctx, cert_file)) + goto bad; + } else { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "skipping local cert check"); + } + } + + /* Initialize TLS 1.2 1.3 ciphersuites. */ + if (!init_tls_ciphersuites(ctx, ciphers_v12, ciphers_v13)) { + goto bad; + } + + /* + * Load diffie-hellman parameters from a file if specified. + * Failure to open the file is not a fatal error. + */ + if (dhparam_file != NULL) { + FILE *fp = fopen(dhparam_file, "r"); + if (fp != NULL) { + DH *dhparams = PEM_read_DHparams(fp, NULL, NULL, NULL); + if (dhparams != NULL) { + if (!SSL_CTX_set_tmp_dh(ctx, dhparams)) { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to set diffie-hellman parameters: %s"), + errstr); + DH_free(dhparams); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "loaded diffie-hellman parameters from %s", dhparam_file); + } + } else { + errstr = ERR_reason_error_string(ERR_get_error()); + sudo_warnx(U_("unable to read diffie-hellman parameters: %s"), + errstr); + } + fclose(fp); + } else { + sudo_warn(U_("unable to open %s"), dhparam_file); + } + } else { + sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, + "dhparam file not specified, using default parameters"); + } + + goto done; + +bad: + SSL_CTX_free(ctx); + ctx = NULL; + +done: + debug_return_ptr(ctx); +} +#endif /* HAVE_OPENSSL */