浏览代码

Move common SSL functions to separate file.

Doug Nazar 2 年之前
父节点
当前提交
16f4ba5515
共有 7 个文件被更改,包括 418 次插入554 次删除
  1. 2 1
      configure
  2. 47 0
      include/ssl.h
  3. 2 0
      macros/ax_nagios_get_ssl
  4. 9 5
      src/Makefile.in
  5. 47 275
      src/check_nrpe.c
  6. 24 273
      src/nrpe.c
  7. 287 0
      src/ssl.c

+ 2 - 1
configure

@@ -627,6 +627,7 @@ ac_subst_vars='PERL
 SSL_DH_HEADER_MAKE
 sslbin
 PKG_CONFIG
+SSL_OBJS
 SSL_DH_HEADER
 SSL_LIB_DIR
 SSL_INC_PREFIX
@@ -7390,7 +7391,6 @@ if test "${with_ssl_lib+set}" = set; then :
 fi
 
 
-#auto_dh=yes
 # Check whether --enable-auto_dh was given.
 if test "${enable_auto_dh+set}" = set; then :
   enableval=$enable_auto_dh; auto_dh=no
@@ -7724,6 +7724,7 @@ if ac_fn_c_try_link "$LINENO"; then :
 
 				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
+				SSL_OBJS="ssl.o"
 
 
 else

+ 47 - 0
include/ssl.h

@@ -0,0 +1,47 @@
+/* SSL/TLS parameters */
+typedef enum _SSL_VER {
+	SSL_Ver_Invalid = 0, SSLv2 = 1, SSLv2_plus, SSLv3, SSLv3_plus,
+	TLSv1, TLSv1_plus, TLSv1_1, TLSv1_1_plus, TLSv1_2, TLSv1_2_plus, TLSv1_3, TLSv1_3_plus
+} SslVer;
+
+typedef enum _CLNT_CERTS {
+	ClntCerts_Unknown = 0, Ask_For_Cert = 1, Require_Cert = 2
+} ClntCerts;
+
+typedef enum _SSL_LOGGING {
+	SSL_NoLogging = 0, SSL_LogStartup = 1, SSL_LogIpAddr = 2,
+	SSL_LogVersion = 4, SSL_LogCipher = 8, SSL_LogIfClientCert = 16,
+	SSL_LogCertDetails = 32
+} SslLogging;
+
+typedef struct _SSL_PARMS {
+	char     *cert_file;
+	char     *cacert_file;
+	char     *privatekey_file;
+	char      cipher_list[MAX_FILENAME_LENGTH];
+	SslVer    ssl_proto_ver;
+	int       allowDH;
+	ClntCerts client_certs;
+	SslLogging log_opts;
+} SslParms;
+
+
+#ifdef HAVE_SSL
+# if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
+extern SSL_METHOD *meth;
+# else
+extern const SSL_METHOD *meth;
+# endif
+extern SSL_CTX  *ctx;
+extern SslParms sslprm;
+#endif
+
+extern int       use_ssl;
+
+
+void ssl_initialize(void);
+void ssl_set_protocol_version(SslVer ssl_proto_ver, unsigned long *ssl_opts);
+void ssl_log_startup(int server);
+int ssl_load_certificates(void);
+int ssl_set_ciphers(void);
+int ssl_verify_callback_common(int preverify_ok, X509_STORE_CTX * ctx, int is_invalid);

+ 2 - 0
macros/ax_nagios_get_ssl

@@ -63,6 +63,7 @@ AC_SUBST(SSL_HDR)
 AC_SUBST(SSL_INC_PREFIX)
 AC_SUBST(SSL_LIB_DIR)
 AC_SUBST(SSL_DH_HEADER)
+AC_SUBST(SSL_OBJS)
 
 
 dnl Makefile for generating DH parameters, pre 3.0 and post 3.0
@@ -296,6 +297,7 @@ if test x$SSL_TYPE != xNONE; then
 			[AC_LANG_PROGRAM([#include <${SSL_INC_PREFIX}${SSL_HDR}>], [SSL_new(NULL)])],
 			[
 				AC_MSG_RESULT([yes])
+				SSL_OBJS="ssl.o"
 				$1
 			], [
 				AC_MSG_ERROR([no])

+ 9 - 5
src/Makefile.in

@@ -41,19 +41,23 @@ SNPRINTF_O=@SNPRINTF_O@
 
 SSLBIN=@sslbin@
 SSL_DH_HEADER=@SSL_DH_HEADER@
+SSL_OBJS=@SSL_OBJS@
 
 
 all: nrpe check_nrpe
 
-nrpe: $(srcdir)/nrpe.c utils.o $(srcdir)/acl.c $(SRC_INCLUDE)/nrpe.h $(SRC_INCLUDE)/utils.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h $(SRC_INCLUDE)/acl.h $(SNPRINTF_O) $(SSL_DH_HEADER)
-	$(CC) $(CFLAGS) -o $@ $(srcdir)/nrpe.c utils.o $(srcdir)/acl.c $(LDFLAGS) $(SOCKETLIBS) $(LIBWRAPLIBS) $(SNPRINTF_O) $(OTHERLIBS)
+nrpe: $(srcdir)/nrpe.c utils.o $(srcdir)/acl.c $(SRC_INCLUDE)/nrpe.h $(SRC_INCLUDE)/utils.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h $(SRC_INCLUDE)/acl.h $(SNPRINTF_O) $(SSL_DH_HEADER) $(SSL_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(srcdir)/nrpe.c utils.o $(SSL_OBJS) $(srcdir)/acl.c $(LDFLAGS) $(SOCKETLIBS) $(LIBWRAPLIBS) $(SNPRINTF_O) $(OTHERLIBS)
 
-check_nrpe: $(srcdir)/check_nrpe.c utils.o $(SRC_INCLUDE)/utils.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h
-	$(CC) $(CFLAGS) -o $@ $(srcdir)/check_nrpe.c utils.o $(LDFLAGS) $(SOCKETLIBS) $(SNPRINTF_O) $(OTHERLIBS)
+check_nrpe: $(srcdir)/check_nrpe.c utils.o $(SRC_INCLUDE)/utils.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h $(SSL_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(srcdir)/check_nrpe.c utils.o $(SSL_OBJS) $(LDFLAGS) $(SOCKETLIBS) $(SNPRINTF_O) $(OTHERLIBS)
 
 utils.o: $(srcdir)/utils.c $(SRC_INCLUDE)/utils.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h
 	$(CC) $(CFLAGS) -c -o $@ $(srcdir)/utils.c
 
+ssl.o: $(srcdir)/ssl.c $(SRC_INCLUDE)/ssl.h $(CFG_INCLUDE)/common.h $(CFG_INCLUDE)/config.h
+	$(CC) $(CFLAGS) -c -o $@ $(srcdir)/ssl.c
+
 @SSL_DH_HEADER_MAKE@
 
 
@@ -84,7 +88,7 @@ install-uninstall:
 	$(INSTALL) -m 755 ../uninstall $(SBINDIR)/nrpe-uninstall
 
 clean:
-	rm -f core nrpe check_nrpe generate_dh_params utils.o $(SNPRINTF_O) $(SSL_DH_HEADER)
+	rm -f core nrpe check_nrpe generate_dh_params utils.o ssl.o $(SNPRINTF_O) $(SSL_DH_HEADER)
 	rm -f *~ */*~
 	rm -rf nrpe.dSYM check_nrpe.dSYM
 

+ 47 - 275
src/check_nrpe.c

@@ -41,6 +41,7 @@
 #endif
 #include "common.h"
 #include "utils.h"
+#include "ssl.h"
 
 #define DEFAULT_NRPE_COMMAND "_NRPE_CHECK"	/* check version of NRPE daemon */
 
@@ -73,46 +74,15 @@ int force_v3_packet = 0;
 int payload_size = 0;
 extern char *log_file;
 
+
 #ifdef HAVE_SSL
-# if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
-SSL_METHOD *meth;
-# else
-const SSL_METHOD *meth;
-# endif
-SSL_CTX *ctx;
 SSL *ssl;
-int use_ssl = TRUE;
 unsigned long ssl_opts = SSL_OP_ALL;
-#else
-int use_ssl = FALSE;
 #endif
-
-/* SSL/TLS parameters */
-typedef enum _SSL_VER {
-	SSL_Ver_Invalid = 0, SSLv2 = 1, SSLv2_plus, SSLv3, SSLv3_plus,
-	TLSv1, TLSv1_plus, TLSv1_1, TLSv1_1_plus, TLSv1_2, TLSv1_2_plus, TLSv1_3, TLSv1_3_plus
-} SslVer;
-
-typedef enum _CLNT_CERTS { Ask_For_Cert = 1, Require_Cert = 2 } ClntCerts;
-
-typedef enum _SSL_LOGGING {
-	SSL_NoLogging = 0, SSL_LogStartup = 1, SSL_LogIpAddr = 2,
-	SSL_LogVersion = 4, SSL_LogCipher = 8, SSL_LogIfClientCert = 16,
-	SSL_LogCertDetails = 32,
-} SslLogging;
-
-struct _SSL_PARMS {
-	char *cert_file;
-	char *cacert_file;
-	char *privatekey_file;
-	char cipher_list[MAX_FILENAME_LENGTH];
-	SslVer ssl_proto_ver;
-	int allowDH;
-	ClntCerts client_certs;
-	SslLogging log_opts;
-} sslprm = {
-NULL, NULL, NULL, "", SSL_Ver_Invalid, -1, 0, SSL_NoLogging};
 int have_log_opts = FALSE;
+SslParms sslprm = {
+	NULL, NULL, NULL, "", SSL_Ver_Invalid, -1, 0, SSL_NoLogging
+};
 
 int process_arguments(int, char **, int);
 int read_config_file(char *);
@@ -744,8 +714,10 @@ void usage(int result)
 		printf("                              SSLv2     SSL v2 only\n");
 		printf("                              SSLv2+    SSL v2 or above\n");
 #endif
+#if OPENSSL_VERSION_NUMBER < 0x30000000
 		printf("                              SSLv3     SSL v3 only\n");
 		printf("                              SSLv3+    SSL v3 or above \n");
+#endif
 		printf("                              TLSv1     TLS v1 only\n");
 		printf("                              TLSv1+    TLS v1 or above (DEFAULT)\n");
 		printf("                              TLSv1.1   TLS v1.1 only\n");
@@ -799,244 +771,67 @@ void usage(int result)
 void setup_ssl()
 {
 #ifdef HAVE_SSL
-	int vrfy, x;
-
-	if (sslprm.log_opts & SSL_LogStartup) {
-		char *val;
+	int vrfy;
 
-		logit(LOG_INFO, "SSL Certificate File: %s", sslprm.cert_file ? sslprm.cert_file : "None");
-		logit(LOG_INFO, "SSL Private Key File: %s", sslprm.privatekey_file ? sslprm.privatekey_file : "None");
-		logit(LOG_INFO, "SSL CA Certificate File: %s", sslprm.cacert_file ? sslprm.cacert_file : "None");
-		logit(LOG_INFO, "SSL Cipher List: %s", sslprm.cipher_list);
-		logit(LOG_INFO, "SSL Allow ADH: %d", sslprm.allowDH);
-		logit(LOG_INFO, "SSL Log Options: 0x%02x", sslprm.log_opts);
-
-		switch (sslprm.ssl_proto_ver) {
-		case SSLv2:
-			val = "SSLv2";
-			break;
-		case SSLv2_plus:
-			val = "SSLv2 And Above";
-			break;
-		case SSLv3:
-			val = "SSLv3";
-			break;
-		case SSLv3_plus:
-			val = "SSLv3_plus And Above";
-			break;
-		case TLSv1:
-			val = "TLSv1";
-			break;
-		case TLSv1_plus:
-			val = "TLSv1_plus And Above";
-			break;
-		case TLSv1_1:
-			val = "TLSv1_1";
-			break;
-		case TLSv1_1_plus:
-			val = "TLSv1_1_plus And Above";
-			break;
-		case TLSv1_2:
-			val = "TLSv1_2";
-			break;
-		case TLSv1_2_plus:
-			val = "TLSv1_2_plus And Above";
-			break;
-		case TLSv1_3:
-			val = "TLSv1_3";
-			break;
-		case TLSv1_3_plus:
-			val = "TLSv1_3_plus And Above";
-			break;
-		default:
-			val = "INVALID VALUE!";
-			break;
-		}
-		logit(LOG_INFO, "SSL Version: %s", val);
-	}
+	if (sslprm.log_opts & SSL_LogStartup)
+		ssl_log_startup(FALSE);
 
 	/* initialize SSL */
-	if (use_ssl == TRUE) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000
-		SSL_load_error_strings();
-		SSL_library_init();
-		ENGINE_load_builtin_engines();
-		RAND_set_rand_engine(NULL);
- 		ENGINE_register_all_complete();
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000
+	if (use_ssl == FALSE)
+		return;
 
-		meth = TLS_method();
+	ssl_initialize();
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+	meth = TLS_client_method();
 #else		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
-		meth = SSLv23_client_method();
-
+	meth = SSLv23_client_method();
 # ifndef OPENSSL_NO_SSL2
-		if (sslprm.ssl_proto_ver == SSLv2)
-			meth = SSLv2_client_method();
+	if (sslprm.ssl_proto_ver == SSLv2)
+		meth = SSLv2_client_method();
 # endif
 # ifndef OPENSSL_NO_SSL3
-		if (sslprm.ssl_proto_ver == SSLv3)
-			meth = SSLv3_client_method();
+	if (sslprm.ssl_proto_ver == SSLv3)
+		meth = SSLv3_client_method();
 # endif
-		if (sslprm.ssl_proto_ver == TLSv1)
-			meth = TLSv1_client_method();
+	if (sslprm.ssl_proto_ver == TLSv1)
+		meth = TLSv1_client_method();
 # ifdef SSL_TXT_TLSV1_1
-		if (sslprm.ssl_proto_ver == TLSv1_1)
-			meth = TLSv1_1_client_method();
+	if (sslprm.ssl_proto_ver == TLSv1_1)
+		meth = TLSv1_1_client_method();
 #  ifdef SSL_TXT_TLSV1_2
-		if (sslprm.ssl_proto_ver == TLSv1_2)
-			meth = TLSv1_2_client_method();
-#  ifdef SSL_TXT_TLSV1_3
-		if (sslprm.ssl_proto_ver == TLSv1_3)
-			meth = TLSv1_3_client_method();
-#  endif	/* ifdef SSL_TXT_TLSV1_3 */
+	if (sslprm.ssl_proto_ver == TLSv1_2)
+		meth = TLSv1_2_client_method();
+#   ifdef SSL_TXT_TLSV1_3
+	if (sslprm.ssl_proto_ver == TLSv1_3)
+		meth = TLSv1_3_client_method();
+#   endif	/* ifdef SSL_TXT_TLSV1_3 */
 #  endif	/* ifdef SSL_TXT_TLSV1_2 */
 # endif	/* ifdef SSL_TXT_TLSV1_1 */
 
 #endif		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
 
-		if ((ctx = SSL_CTX_new(meth)) == NULL) {
-			printf("CHECK_NRPE: Error - could not create SSL context.\n");
-			exit(timeout_return_code);
-		}
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000
-
-	SSL_CTX_set_max_proto_version(ctx, 0);
-
-	switch(sslprm.ssl_proto_ver) {
-		case TLSv1_3:
-#if OPENSSL_VERSION_NUMBER >= 0x10101000
-			SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
-#endif
-		case TLSv1_3_plus:
-#if OPENSSL_VERSION_NUMBER >= 0x10101000
-			SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
-			break;
-#endif
-
-		case TLSv1_2:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
-		case TLSv1_2_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
-			break;
-
-		case TLSv1_1:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
-		case TLSv1_1_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
-			break;
-
-		case TLSv1:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
-		case TLSv1_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
-			break;
-
-		case SSLv3:
-			SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
-		case SSLv3_plus:
-			SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
-			break;
+	if ((ctx = SSL_CTX_new(meth)) == NULL) {
+		printf("CHECK_NRPE: Error - could not create SSL context.\n");
+		exit(timeout_return_code);
 	}
 
-#else		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
-		switch(sslprm.ssl_proto_ver) {
-			case SSLv2:
-			case SSLv2_plus:
-				break;
-			case TLSv1_3:
-			case TLSv1_3_plus:
-#ifdef SSL_OP_NO_TLSv1_2
-				ssl_opts |= SSL_OP_NO_TLSv1_2;
-#endif
-			case TLSv1_2:
-			case TLSv1_2_plus:
-#ifdef SSL_OP_NO_TLSv1_1
-				ssl_opts |= SSL_OP_NO_TLSv1_1;
-#endif
-			case TLSv1_1:
-			case TLSv1_1_plus:
-				ssl_opts |= SSL_OP_NO_TLSv1;
-			case TLSv1:
-			case TLSv1_plus:
-				ssl_opts |= SSL_OP_NO_SSLv3;
-			case SSLv3:
-			case SSLv3_plus:
-				ssl_opts |= SSL_OP_NO_SSLv2;
-				break;
-			case SSL_Ver_Invalid:
-				/* Should never be seen, silence warning */
-				break;
-		}
-
-#endif		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
-		SSL_CTX_set_options(ctx, ssl_opts);
-
-		if (sslprm.cert_file != NULL && sslprm.privatekey_file != NULL) {
-			if (!SSL_CTX_use_certificate_chain_file(ctx, sslprm.cert_file)) {
-				printf("Error: could not use certificate file '%s'.\n", sslprm.cert_file);
-				while ((x = ERR_get_error()) != 0) {
-					printf("Error: could not use certificate file '%s': %s\n", sslprm.cert_file, ERR_reason_error_string(x));
-				}
-				SSL_CTX_free(ctx);
-				exit(timeout_return_code);
-			}
-			if (!SSL_CTX_use_PrivateKey_file(ctx, sslprm.privatekey_file, SSL_FILETYPE_PEM)) {
-				SSL_CTX_free(ctx);
-				printf("Error: could not use private key file '%s'.\n", sslprm.privatekey_file);
-				while ((x = ERR_get_error()) != 0) {
-					printf("Error: could not use private key file '%s': %s\n", sslprm.privatekey_file, ERR_reason_error_string(x));
-				}
-				SSL_CTX_free(ctx);
-				exit(timeout_return_code);
-			}
-		}
+	ssl_set_protocol_version(sslprm.ssl_proto_ver, &ssl_opts);
+	SSL_CTX_set_options(ctx, ssl_opts);
 
-		if (sslprm.cacert_file != NULL) {
-			vrfy = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-			SSL_CTX_set_verify(ctx, vrfy, verify_callback);
-			if (!SSL_CTX_load_verify_locations(ctx, sslprm.cacert_file, NULL)) {
-				printf("Error: could not use CA certificate '%s'.\n", sslprm.cacert_file);
-				while ((x = ERR_get_error()) != 0) {
-					printf("Error: could not use CA certificate '%s': %s\n", sslprm.cacert_file, ERR_reason_error_string(x));
-				}
-				SSL_CTX_free(ctx);
-				exit(timeout_return_code);
-			}
-		}
+	if (!ssl_load_certificates()) {
+		SSL_CTX_free(ctx);
+		exit(timeout_return_code);
+	}
 
-		if (!sslprm.allowDH) {
-			x = strlen(sslprm.cipher_list);
-			if (x < sizeof(sslprm.cipher_list) - 6) {
-				strncpy(sslprm.cipher_list + x, ":!ADH", sizeof(sslprm.cipher_list) - x);
-				if (sslprm.log_opts & SSL_LogStartup)
-					logit(LOG_INFO, "New SSL Cipher List: %s", sslprm.cipher_list);
-			}
-		} else {
-			/* use anonymous DH ciphers */
-			if (sslprm.allowDH == 2) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000
-				strncpy(sslprm.cipher_list, "ADH@SECLEVEL=0", MAX_FILENAME_LENGTH - 1);
-#else
-				strncpy(sslprm.cipher_list, "ADH", MAX_FILENAME_LENGTH - 1);
-#endif
-			}
-		}
+	if (sslprm.cacert_file != NULL) {
+		vrfy = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+		SSL_CTX_set_verify(ctx, vrfy, verify_callback);
+	}
 
-		if (SSL_CTX_set_cipher_list(ctx, sslprm.cipher_list) == 0) {
-			printf("Error: Could not set SSL/TLS cipher list: %s\n", sslprm.cipher_list);
-			while ((x = ERR_get_error()) != 0) {
-				printf("Could not set SSL/TLS cipher list '%s': %s\n", sslprm.cipher_list, ERR_reason_error_string(x));
-			}
-			SSL_CTX_free(ctx);
-			exit(timeout_return_code);
-		}
+	if (!ssl_set_ciphers()) {
+		SSL_CTX_free(ctx);
+		exit(timeout_return_code);
 	}
 #endif
 }
@@ -1641,30 +1436,7 @@ int read_packet(int sock, void *ssl_ptr, v2_packet ** v2_pkt, v3_packet ** v3_pk
 #ifdef HAVE_SSL
 int verify_callback(int preverify_ok, X509_STORE_CTX * ctx)
 {
-	char name[256], issuer[256];
-	X509 *err_cert;
-	int err;
-	SSL *ssl;
-
-	if (preverify_ok || ((sslprm.log_opts & SSL_LogCertDetails) == 0))
-		return preverify_ok;
-
-	err_cert = X509_STORE_CTX_get_current_cert(ctx);
-	err = X509_STORE_CTX_get_error(ctx);
-
-	/* Get the pointer to the SSL of the current connection */
-	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-
-	X509_NAME_oneline(X509_get_subject_name(err_cert), name, 256);
-	X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);
-
-	if (!preverify_ok && sslprm.client_certs >= Ask_For_Cert
-		&& (sslprm.log_opts & SSL_LogCertDetails)) {
-		
-		logit(LOG_ERR, "SSL Client has an invalid certificate: %s (issuer=%s) err=%d:%s", name, issuer, err, X509_verify_cert_error_string(err));
-	}
-
-	return preverify_ok;
+	return ssl_verify_callback_common(preverify_ok, ctx, !preverify_ok && sslprm.client_certs >= Ask_For_Cert);
 }
 #endif
 

+ 24 - 273
src/nrpe.c

@@ -41,6 +41,7 @@
 #include "nrpe.h"
 #include "utils.h"
 #include "acl.h"
+#include "ssl.h"
 
 #ifdef HAVE_SSL
 # if defined(USE_SSL_DH) && !defined(AUTO_SSL_DH)
@@ -60,17 +61,6 @@ int       rfc931_timeout=15;
 # endif
 #endif
 
-#ifdef HAVE_SSL
-# if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
-SSL_METHOD *meth;
-# else
-const SSL_METHOD *meth;
-# endif
-SSL_CTX  *ctx;
-int       use_ssl = TRUE;
-#else
-int       use_ssl = FALSE;
-#endif
 
 #define DEFAULT_COMMAND_TIMEOUT			60	/* default timeout for execution of plugins */
 #define MAXFD							64
@@ -124,32 +114,8 @@ int       listen_queue_size = DEFAULT_LISTEN_QUEUE_SIZE;
 char     *nasty_metachars = NULL;
 extern char *log_file;
 
-/* SSL/TLS parameters */
-typedef enum _SSL_VER {
-	SSLv2 = 1, SSLv2_plus, SSLv3, SSLv3_plus, TLSv1,
-	TLSv1_plus, TLSv1_1, TLSv1_1_plus, TLSv1_2, TLSv1_2_plus, TLSv1_3, TLSv1_3_plus
-} SslVer;
-
-typedef enum _CLNT_CERTS {
-	ClntCerts_Unknown = 0, Ask_For_Cert = 1, Require_Cert = 2
-} ClntCerts;
-
-typedef enum _SSL_LOGGING {
-	SSL_NoLogging = 0, SSL_LogStartup = 1, SSL_LogIpAddr = 2,
-	SSL_LogVersion = 4, SSL_LogCipher = 8, SSL_LogIfClientCert = 16,
-	SSL_LogCertDetails = 32
-} SslLogging;
-
-struct _SSL_PARMS {
-	char     *cert_file;
-	char     *cacert_file;
-	char     *privatekey_file;
-	char      cipher_list[MAX_FILENAME_LENGTH];
-	SslVer    ssl_proto_ver;
-	int       allowDH;
-	ClntCerts client_certs;
-	SslLogging log_opts;
-} sslprm = {
+
+SslParms sslprm = {
 #if OPENSSL_VERSION_NUMBER >= 0x10100000
 NULL, NULL, NULL, "ALL:!MD5:@STRENGTH:@SECLEVEL=0", TLSv1_plus, TRUE, 0, SSL_NoLogging
 #else
@@ -287,16 +253,10 @@ void init_ssl(void)
 #endif
 
 	if (sslprm.log_opts & SSL_LogStartup)
-		log_ssl_startup();
+		ssl_log_startup(TRUE);
+
+	ssl_initialize();
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000
-	/* initialize SSL */
-	SSL_load_error_strings();
-	SSL_library_init();
-	ENGINE_load_builtin_engines();
-	RAND_set_rand_engine(NULL);
- 	ENGINE_register_all_complete();
-#endif
 	/* use week random seed if necessary */
 	if (allow_weak_random_seed && (RAND_status() == 0)) {
 		if (RAND_file_name(seedfile, sizeof(seedfile) - 1))
@@ -317,11 +277,8 @@ void init_ssl(void)
 	}
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000
-
-	meth = TLS_method();
-
+	meth = TLS_server_method();
 #else		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
 	meth = SSLv23_server_method();
 # ifndef OPENSSL_NO_SSL2
 	if (sslprm.ssl_proto_ver == SSLv2)
@@ -354,122 +311,15 @@ void init_ssl(void)
 			ERR_error_string(x, errstr);
 			logit(LOG_ERR, "Error: could not create SSL context : %s", errstr);
 		}
-		SSL_CTX_free(ctx);
 		exit(STATE_CRITICAL);
 	}
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000
-
-	SSL_CTX_set_max_proto_version(ctx, 0);
-
-	switch(sslprm.ssl_proto_ver) {
-		case TLSv1_3:
-#if OPENSSL_VERSION_NUMBER >= 0x10101000
-			SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
-#endif
-		case TLSv1_3_plus:
-#if OPENSSL_VERSION_NUMBER >= 0x10101000
-			SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
-			break;
-#endif
-
-		case TLSv1_2:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
-		case TLSv1_2_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
-			break;
-
-		case TLSv1_1:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
-		case TLSv1_1_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
-			break;
-
-		case TLSv1:
-			SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
-		case TLSv1_plus:
-			SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
-			break;
-
-		case SSLv3:
-			SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
-		case SSLv3_plus:
-			SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
-			break;
-	}
-
-#else		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
-	switch(sslprm.ssl_proto_ver) {
-		case SSLv2:
-		case SSLv2_plus:
-			break;
-		case TLSv1_3:
-		case TLSv1_3_plus:
-#ifdef SSL_OP_NO_TLSv1_2
-			ssl_opts |= SSL_OP_NO_TLSv1_2;
-#endif
-		case TLSv1_2:
-		case TLSv1_2_plus:
-#ifdef SSL_OP_NO_TLSv1_1
-			ssl_opts |= SSL_OP_NO_TLSv1_1;
-#endif
-		case TLSv1_1:
-		case TLSv1_1_plus:
-			ssl_opts |= SSL_OP_NO_TLSv1;
-		case TLSv1:
-		case TLSv1_plus:
-			ssl_opts |= SSL_OP_NO_SSLv3;
-		case SSLv3:
-		case SSLv3_plus:
-			ssl_opts |= SSL_OP_NO_SSLv2;
-			break;
-	}
-
-#endif		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
-
+	ssl_set_protocol_version(sslprm.ssl_proto_ver, &ssl_opts);
 	SSL_CTX_set_options(ctx, ssl_opts);
 
-	if (sslprm.cacert_file != NULL) {
-		if (!SSL_CTX_load_verify_locations(ctx, sslprm.cacert_file, NULL)) {
-			while ((x = ERR_get_error()) != 0) {
-				logit(LOG_ERR, "Error: could not use CA certificate file '%s': %s\n",
-					   sslprm.cacert_file, ERR_reason_error_string(x));
-			}
-			SSL_CTX_free(ctx);
-			logit(LOG_ERR, "Error: could not use CA certificate '%s'", sslprm.cacert_file);
-			exit(STATE_CRITICAL);
-		}
-	}
-
-	if (sslprm.cert_file != NULL) {
-		if (!SSL_CTX_use_certificate_chain_file(ctx, sslprm.cert_file)) {
-			SSL_CTX_free(ctx);
-			while ((x = ERR_get_error()) != 0) {
-				ERR_error_string(x, errstr);
-				logit(LOG_ERR, "Error: could not use certificate file %s : %s",
-					   sslprm.cert_file, errstr);
-			}
-			exit(STATE_CRITICAL);
-		}
-		if (!SSL_CTX_use_PrivateKey_file(ctx, sslprm.privatekey_file, SSL_FILETYPE_PEM)) {
-			while ((x = ERR_get_error()) != 0) {
-				ERR_error_string(x, errstr);
-				logit(LOG_ERR, "Error: could not use private key file '%s' : %s",
-					 sslprm.privatekey_file, errstr);
-			}
-			SSL_CTX_free(ctx);
-			exit(STATE_CRITICAL);
-		}
-		if (!SSL_CTX_check_private_key(ctx)) {
-			while ((x = ERR_get_error()) != 0) {
-				ERR_error_string(x, errstr);
-				logit(LOG_ERR, "Error: could not use certificate/private key pair: %s",
-					 errstr);
-			}
-			SSL_CTX_free(ctx);
-			exit(STATE_CRITICAL);
-		}
+	if (!ssl_load_certificates()) {
+		SSL_CTX_free(ctx);
+		exit(STATE_CRITICAL);
 	}
 
 	if (sslprm.client_certs != 0) {
@@ -486,44 +336,28 @@ void init_ssl(void)
 		SSL_CTX_set_verify(ctx, vrfy, verify_callback);
 	}
 
-	if (!sslprm.allowDH) {
-		i = strlen(sslprm.cipher_list);
-		if (i < sizeof(sslprm.cipher_list) - 6)
-			strncpy(sslprm.cipher_list + i, ":!ADH", sizeof(sslprm.cipher_list) - i);
-	} else {
-		/* use anonymous DH ciphers */
-		if (sslprm.allowDH == 2) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000
-			strncpy(sslprm.cipher_list, "ADH:@SECLEVEL=0", MAX_FILENAME_LENGTH - 1);
-#else
-			strncpy(sslprm.cipher_list, "ADH", MAX_FILENAME_LENGTH - 1);
-#endif
-		}
-
 #ifdef AUTO_SSL_DH
-		SSL_CTX_set_dh_auto(ctx, 1);
+	SSL_CTX_set_dh_auto(ctx, 1);
 #else
 # ifdef USE_SSL_DH
-		{
+	{
 #  if OPENSSL_VERSION_NUMBER >= 0x30000000
-			EVP_PKEY *pkey = get_dh2048_key();
-			if (pkey) {
-					if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
-						EVP_PKEY_free(pkey);
-			}
+		EVP_PKEY *pkey = get_dh2048_key();
+		if (pkey) {
+				if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
+					EVP_PKEY_free(pkey);
+		}
 #  else
-			DH *dh = get_dh2048();
-			SSL_CTX_set_tmp_dh(ctx, dh);
-			DH_free(dh);
+		DH *dh = get_dh2048();
+		SSL_CTX_set_tmp_dh(ctx, dh);
+		DH_free(dh);
 #  endif
-		}
+	}
 # endif
 #endif
-	}
 
-	if (SSL_CTX_set_cipher_list(ctx, sslprm.cipher_list) == 0) {
+	if (!ssl_set_ciphers()) {
 		SSL_CTX_free(ctx);
-		logit(LOG_ERR, "Error: Could not set SSL/TLS cipher list");
 		exit(STATE_CRITICAL);
 	}
 
@@ -532,67 +366,6 @@ void init_ssl(void)
 #endif
 }
 
-void log_ssl_startup(void)
-{
-#ifdef HAVE_SSL
-	char     *vers;
-
-	logit(LOG_INFO, "SSL Certificate File: %s", sslprm.cert_file ? sslprm.cert_file : "None");
-	logit(LOG_INFO, "SSL Private Key File: %s",
-		   sslprm.privatekey_file ? sslprm.privatekey_file : "None");
-	logit(LOG_INFO, "SSL CA Certificate File: %s",
-		   sslprm.cacert_file ? sslprm.cacert_file : "None");
-	logit(LOG_INFO, "SSL Cipher List: %s", sslprm.cipher_list);
-	logit(LOG_INFO, "SSL Allow ADH: %d", sslprm.allowDH);
-	logit(LOG_INFO, "SSL Client Certs: %s",
-		   sslprm.client_certs == 0 ? "Don't Ask" : (sslprm.client_certs ==
-													 1 ? "Accept" : "Require"));
-	logit(LOG_INFO, "SSL Log Options: 0x%02x", sslprm.log_opts);
-	switch (sslprm.ssl_proto_ver) {
-	case SSLv2:
-		vers = "SSLv2";
-		break;
-	case SSLv2_plus:
-		vers = "SSLv2 And Above";
-		break;
-	case SSLv3:
-		vers = "SSLv3";
-		break;
-	case SSLv3_plus:
-		vers = "SSLv3 And Above";
-		break;
-	case TLSv1:
-		vers = "TLSv1";
-		break;
-	case TLSv1_plus:
-		vers = "TLSv1 And Above";
-		break;
-	case TLSv1_1:
-		vers = "TLSv1_1";
-		break;
-	case TLSv1_1_plus:
-		vers = "TLSv1_1 And Above";
-		break;
-	case TLSv1_2:
-		vers = "TLSv1_2";
-		break;
-	case TLSv1_2_plus:
-		vers = "TLSv1_2 And Above";
-		break;
-	case TLSv1_3:
-		vers = "TLSv1_3";
-		break;
-	case TLSv1_3_plus:
-		vers = "TLSv1_3 And Above";
-		break;
-	default:
-		vers = "INVALID VALUE!";
-		break;
-	}
-	logit(LOG_INFO, "SSL Version: %s", vers);
-#endif
-}
-
 void usage(int result)
 {
 	if (result != OK) {
@@ -787,29 +560,7 @@ void cleanup(void)
 #ifdef HAVE_SSL
 int verify_callback(int preverify_ok, X509_STORE_CTX * ctx)
 {
-	char      name[256], issuer[256];
-	X509     *err_cert;
-	int       err;
-	SSL      *ssl;
-
-	if (preverify_ok || ((sslprm.log_opts & SSL_LogCertDetails) == 0))
-		return preverify_ok;
-
-	err_cert = X509_STORE_CTX_get_current_cert(ctx);
-	err = X509_STORE_CTX_get_error(ctx);
-
-	/* Get the pointer to the SSL of the current connection */
-	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-
-	X509_NAME_oneline(X509_get_subject_name(err_cert), name, 256);
-	X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);
-
-	if (!preverify_ok && (sslprm.log_opts & SSL_LogCertDetails)) {
-		logit(LOG_ERR, "SSL Client has an invalid certificate: %s (issuer=%s) err=%d:%s",
-			   name, issuer, err, X509_verify_cert_error_string(err));
-	}
-
-	return preverify_ok;
+	return ssl_verify_callback_common(preverify_ok, ctx, !preverify_ok);
 }
 #endif
 

+ 287 - 0
src/ssl.c

@@ -0,0 +1,287 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "common.h"
+#include "ssl.h"
+#include "utils.h"
+
+#ifdef HAVE_SSL
+# if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
+SSL_METHOD *meth;
+# else
+const SSL_METHOD *meth;
+# endif
+SSL_CTX  *ctx;
+int       use_ssl = TRUE;
+#else
+int       use_ssl = FALSE;
+#endif
+
+
+
+void ssl_initialize(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000
+	/* initialize SSL */
+	SSL_load_error_strings();
+	SSL_library_init();
+	ENGINE_load_builtin_engines();
+	RAND_set_rand_engine(NULL);
+ 	ENGINE_register_all_complete();
+#endif
+}
+
+void ssl_set_protocol_version(SslVer ssl_proto_ver, unsigned long *ssl_opts)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+
+	SSL_CTX_set_max_proto_version(ctx, 0);
+
+	switch(ssl_proto_ver) {
+		case TLSv1_3:
+#if OPENSSL_VERSION_NUMBER >= 0x10101000
+			SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
+#endif
+		case TLSv1_3_plus:
+#if OPENSSL_VERSION_NUMBER >= 0x10101000
+			SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
+			break;
+#endif
+
+		case TLSv1_2:
+			SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
+		case TLSv1_2_plus:
+			SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
+			break;
+
+		case TLSv1_1:
+			SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
+		case TLSv1_1_plus:
+			SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
+			break;
+
+		case TLSv1:
+			SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
+		case TLSv1_plus:
+			SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
+			break;
+
+		case SSLv3:
+			SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
+		case SSLv3_plus:
+			SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
+			break;
+
+		case SSLv2:
+		case SSLv2_plus:
+			/* SSLv2 support dropped */
+			break;
+		case SSL_Ver_Invalid:
+			/* Should never be seen, silence warning */
+			break;
+	}
+
+#else		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
+
+	switch(sslprm.ssl_proto_ver) {
+		case SSLv2:
+		case SSLv2_plus:
+			break;
+		case TLSv1_3:
+		case TLSv1_3_plus:
+#ifdef SSL_OP_NO_TLSv1_2
+			*ssl_opts |= SSL_OP_NO_TLSv1_2;
+#endif
+		case TLSv1_2:
+		case TLSv1_2_plus:
+#ifdef SSL_OP_NO_TLSv1_1
+			*ssl_opts |= SSL_OP_NO_TLSv1_1;
+#endif
+		case TLSv1_1:
+		case TLSv1_1_plus:
+			*ssl_opts |= SSL_OP_NO_TLSv1;
+		case TLSv1:
+		case TLSv1_plus:
+			*ssl_opts |= SSL_OP_NO_SSLv3;
+		case SSLv3:
+		case SSLv3_plus:
+			*ssl_opts |= SSL_OP_NO_SSLv2;
+			break;
+        case SSL_Ver_Invalid:
+            /* Should never be seen, silence warning */
+            break;
+	}
+#endif		/* OPENSSL_VERSION_NUMBER >= 0x10100000 */
+}
+
+void ssl_log_startup(int server)
+{
+	char     *vers;
+
+	logit(LOG_INFO, "SSL Certificate File: %s", sslprm.cert_file ? sslprm.cert_file : "None");
+	logit(LOG_INFO, "SSL Private Key File: %s", sslprm.privatekey_file ? sslprm.privatekey_file : "None");
+	logit(LOG_INFO, "SSL CA Certificate File: %s", sslprm.cacert_file ? sslprm.cacert_file : "None");
+	logit(LOG_INFO, "SSL Cipher List: %s", sslprm.cipher_list);
+	logit(LOG_INFO, "SSL Allow ADH: %d", sslprm.allowDH);
+    if (server)
+    {
+        logit(LOG_INFO, "SSL Client Certs: %s",
+            sslprm.client_certs == 0 ? "Don't Ask" : 
+                (sslprm.client_certs == 1 ? "Accept" : "Require"));
+    }
+	logit(LOG_INFO, "SSL Log Options: 0x%02x", sslprm.log_opts);
+
+	switch (sslprm.ssl_proto_ver) {
+	case SSLv2:
+		vers = "SSLv2";
+		break;
+	case SSLv2_plus:
+		vers = "SSLv2 And Above";
+		break;
+	case SSLv3:
+		vers = "SSLv3";
+		break;
+	case SSLv3_plus:
+		vers = "SSLv3 And Above";
+		break;
+	case TLSv1:
+		vers = "TLSv1";
+		break;
+	case TLSv1_plus:
+		vers = "TLSv1 And Above";
+		break;
+	case TLSv1_1:
+		vers = "TLSv1_1";
+		break;
+	case TLSv1_1_plus:
+		vers = "TLSv1_1 And Above";
+		break;
+	case TLSv1_2:
+		vers = "TLSv1_2";
+		break;
+	case TLSv1_2_plus:
+		vers = "TLSv1_2 And Above";
+		break;
+	case TLSv1_3:
+		vers = "TLSv1_3";
+		break;
+	case TLSv1_3_plus:
+		vers = "TLSv1_3 And Above";
+		break;
+	default:
+		vers = "INVALID VALUE!";
+		break;
+	}
+	logit(LOG_INFO, "SSL Version: %s", vers);
+}
+
+int ssl_load_certificates(void)
+{
+    int x;
+	char errstr[256] = { "" };
+
+	if (sslprm.cacert_file != NULL) {
+		if (!SSL_CTX_load_verify_locations(ctx, sslprm.cacert_file, NULL)) {
+			logit(LOG_ERR, "Error: Could not use CA certificate '%s'", sslprm.cacert_file);
+			while ((x = ERR_get_error()) != 0) {
+				ERR_error_string(x, errstr);
+				logit(LOG_ERR, "     : %s\n", errstr);
+			}
+            return FALSE;
+		}
+	}
+
+	if (sslprm.cert_file != NULL && sslprm.privatekey_file != NULL) {
+		if (!SSL_CTX_use_certificate_chain_file(ctx, sslprm.cert_file)) {
+			logit(LOG_ERR, "Error: Could not use certificate '%s'", sslprm.cert_file);
+			while ((x = ERR_get_error()) != 0) {
+				ERR_error_string(x, errstr);
+				logit(LOG_ERR, "     : %s\n", errstr);
+			}
+            return FALSE;
+		}
+		if (!SSL_CTX_use_PrivateKey_file(ctx, sslprm.privatekey_file, SSL_FILETYPE_PEM)) {
+            logit(LOG_ERR, "Error: Could not use private key file '%s'", sslprm.privatekey_file);
+			while ((x = ERR_get_error()) != 0) {
+				ERR_error_string(x, errstr);
+				logit(LOG_ERR, "     : %s\n", errstr);
+			}
+            return FALSE;
+		}
+		if (!SSL_CTX_check_private_key(ctx)) {
+            logit(LOG_ERR, "Error: Could not use certificate/private key pair");
+			while ((x = ERR_get_error()) != 0) {
+				ERR_error_string(x, errstr);
+				logit(LOG_ERR, "     : %s\n", errstr);
+			}
+            return FALSE;
+		}
+	}
+
+    return TRUE;
+}
+
+int ssl_set_ciphers(void)
+{
+    int x;
+    int changed = FALSE;
+	char errstr[256] = { "" };
+
+    if (!sslprm.allowDH) {
+        x = strlen(sslprm.cipher_list);
+        if (x < sizeof(sslprm.cipher_list) - 6) {
+            changed = TRUE;
+            strncpy(sslprm.cipher_list + x, ":!ADH", sizeof(sslprm.cipher_list) - x);
+        }
+    } else {
+        /* use anonymous DH ciphers */
+        if (sslprm.allowDH == 2) {
+            changed = TRUE;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+            strncpy(sslprm.cipher_list, "ADH:@SECLEVEL=0", MAX_FILENAME_LENGTH - 1);
+#else
+            strncpy(sslprm.cipher_list, "ADH", MAX_FILENAME_LENGTH - 1);
+#endif
+        }
+    }
+
+    if (changed && sslprm.log_opts & SSL_LogStartup)
+        logit(LOG_INFO, "New SSL Cipher List: %s", sslprm.cipher_list);
+
+    if (SSL_CTX_set_cipher_list(ctx, sslprm.cipher_list) == 0) {
+        logit(LOG_ERR, "Error: Could not set SSL/TLS cipher list: %s\n", sslprm.cipher_list);
+        while ((x = ERR_get_error()) != 0) {
+            ERR_error_string(x, errstr);
+            logit(LOG_ERR, "     : %s\n", errstr);
+        }
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+int ssl_verify_callback_common(int preverify_ok, X509_STORE_CTX * ctx, int is_invalid)
+{
+	char name[256], issuer[256];
+	X509 *err_cert;
+	int err;
+
+	if (preverify_ok || ((sslprm.log_opts & SSL_LogCertDetails) == 0))
+		return preverify_ok;
+
+	if (is_invalid || sslprm.log_opts & SSL_LogCertDetails) {
+		err_cert = X509_STORE_CTX_get_current_cert(ctx);
+		err = X509_STORE_CTX_get_error(ctx);
+
+		X509_NAME_oneline(X509_get_subject_name(err_cert), name, 256);
+		X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);
+
+		if (is_invalid) {
+			logit(LOG_ERR, "SSL Client has an invalid certificate: %s (issuer=%s) err=%d:%s", name, issuer, err, X509_verify_cert_error_string(err));
+		} else {
+			logit(LOG_INFO, "SSL Client certificate: %s (issuer=%s)", name, issuer);
+		}
+	}
+
+	return preverify_ok;
+}