https://github.com/eclipse-mosquitto/mosquitto/commit/a9ebf37dabed20c3663b7511f07226d90e259fc1
https://github.com/eclipse-mosquitto/mosquitto/commit/d61d25d488fd8c266c46cc6ca79e9d32417fd8a3

From a9ebf37dabed20c3663b7511f07226d90e259fc1 Mon Sep 17 00:00:00 2001
From: "Roger A. Light" <roger@atchoo.org>
Date: Mon, 26 Feb 2024 19:07:22 +0000
Subject: [PATCH] Remove support for openssl < 3.0

---
 ChangeLog.txt                             |  1 +
 lib/net_mosq.c                            | 48 +-------------
 lib/options.c                             |  8 +--
 lib/tls_mosq.c                            |  8 ---
 src/conf.c                                |  9 +--
 src/handle_connect.c                      |  4 --
 src/http_serv.c                           |  2 +-
 src/mosquitto_broker_internal.h           |  1 -
 src/net.c                                 | 76 -----------------------
 src/security_default.c                    |  4 --
 test/broker/16-config-parse-errors-tls.py |  2 -
 11 files changed, 5 insertions(+), 158 deletions(-)

diff --git a/lib/tls_mosq.c b/lib/tls_mosq.c
index b1054757df..109e182371 100644
--- a/lib/tls_mosq.c
+++ b/lib/tls_mosq.c
@@ -152,22 +152,14 @@ int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname)
 		for(i=0; i<sk_GENERAL_NAME_num(san); i++){
 			nval = sk_GENERAL_NAME_value(san, i);
 			if(nval->type == GEN_DNS){
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-				data = ASN1_STRING_data(nval->d.dNSName);
-#else
 				data = ASN1_STRING_get0_data(nval->d.dNSName);
-#endif
 				if(data && !mosquitto__cmp_hostname_wildcard((char *)data, hostname)){
 					sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
 					return 1;
 				}
 				have_san_dns = true;
 			}else if(nval->type == GEN_IPADD){
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-				data = ASN1_STRING_data(nval->d.iPAddress);
-#else
 				data = ASN1_STRING_get0_data(nval->d.iPAddress);
-#endif
 				if(nval->d.iPAddress->length == 4 && ipv4_ok){
 					if(!memcmp(ipv4_addr, data, 4)){
 						sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
diff --git a/src/security_default.c b/src/security_default.c
index e3812ae332..ca10e52b76 100644
--- a/src/security_default.c
+++ b/src/security_default.c
@@ -1066,11 +1066,7 @@ int mosquitto_security_apply_default(void)
 							security__disconnect_auth(context);
 							continue;
 						}
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-						context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1));
-#else
 						context->username = mosquitto__strdup((char *) ASN1_STRING_get0_data(name_asn1));
-#endif
 						if(!context->username){
 							X509_free(client_cert);
 							security__disconnect_auth(context);

From d61d25d488fd8c266c46cc6ca79e9d32417fd8a3 Mon Sep 17 00:00:00 2001
From: "Roger A. Light" <roger@atchoo.org>
Date: Fri, 18 Jul 2025 07:48:42 +0100
Subject: [PATCH] Replace mosquitto__cmp_hostname_wildcard with openssl
 equivalent

---
 lib/net_mosq.c               |   3 +
 lib/tls_mosq.c               | 148 ++++++-----------------------------
 lib/tls_mosq.h               |   3 +-
 5 files changed, 32 insertions(+), 128 deletions(-)

diff --git a/lib/net_mosq.c b/lib/net_mosq.c
index 755825efca..2c3d184955 100644
--- a/lib/net_mosq.c
+++ b/lib/net_mosq.c
@@ -908,6 +908,9 @@ int net__socket_connect_step3(struct mosquitto *mosq, const char *host)
 			net__socket_close(mosq);
 			return MOSQ_ERR_TLS;
 		}
+		if(tls__set_verify_hostname(mosq, host)){
+			return MOSQ_ERR_TLS;
+		}
 
 		if(net__socket_connect_tls(mosq)){
 			net__socket_close(mosq);
diff --git a/lib/tls_mosq.c b/lib/tls_mosq.c
index 109e182371..9d5ed7ebcb 100644
--- a/lib/tls_mosq.c
+++ b/lib/tls_mosq.c
@@ -41,104 +41,30 @@ SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 #include "logging_mosq.h"
 #include "tls_mosq.h"
 
-extern int tls_ex_index_mosq;
-
 int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
 {
-	/* Preverify should have already checked expiry, revocation.
-	 * We need to verify the hostname. */
-	struct mosquitto *mosq;
-	SSL *ssl;
-	X509 *cert;
-
-	/* Always reject if preverify_ok has failed. */
-	if(!preverify_ok) return 0;
-
-	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-	mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq);
-	if(!mosq) return 0;
-
-	if(mosq->tls_insecure == false
-#ifndef WITH_BROKER
-			&& mosq->port != 0 /* no hostname checking for unix sockets */
-#endif
-			){
-		if(X509_STORE_CTX_get_error_depth(ctx) == 0){
-			/* FIXME - use X509_check_host() etc. for sufficiently new openssl (>=1.1.x) */
-			cert = X509_STORE_CTX_get_current_cert(ctx);
-			/* This is the peer certificate, all others are upwards in the chain. */
-#if defined(WITH_BROKER)
-			preverify_ok = mosquitto__verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address);
-#else
-			preverify_ok = mosquitto__verify_certificate_hostname(cert, mosq->host);
-#endif
-			if (preverify_ok != 1) {
-				log__printf(mosq, MOSQ_LOG_ERR, "Error: host name verification failed.");
-			}
-			return preverify_ok;
-		}else{
-			return preverify_ok;
-		}
-	}else{
-		return preverify_ok;
-	}
-}
-
-static int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname)
-{
-	size_t i;
-	size_t len;
+	UNUSED(ctx);
 
-	if(!certname || !hostname){
-		return 1;
-	}
-
-	if(certname[0] == '*'){
-		if(certname[1] != '.'){
-			return 1;
-		}
-		certname += 2;
-		len = strlen(hostname);
-		for(i=0; i<len-1; i++){
-			if(hostname[i] == '.'){
-				hostname += i+1;
-				break;
-			}
-		}
-		len = strlen(hostname);
-		int dotcount = 0;
-		for(i=0; i<len-1; i++){
-			if(hostname[i] == '.'){
-				dotcount++;
-			}
-		}
-		if(dotcount < 1){
-			/* Exclude e.g. *.com, allow e.g. *.example.com */
-			return 1;
-		}
-		return strcasecmp(certname, hostname);
-	}else{
-		return strcasecmp(certname, hostname);
-	}
+	return preverify_ok;
 }
 
-/* This code is based heavily on the example provided in "Secure Programming
- * Cookbook for C and C++".
- */
-int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname)
+int tls__set_verify_hostname(struct mosquitto *mosq, const char *hostname)
 {
-	int i;
-	char name[256];
-	X509_NAME *subj;
-	bool have_san_dns = false;
-	STACK_OF(GENERAL_NAME) *san;
-	const GENERAL_NAME *nval;
-	const unsigned char *data;
 	unsigned char ipv6_addr[16];
 	unsigned char ipv4_addr[4];
 	int ipv6_ok;
 	int ipv4_ok;
+	int rc;
 
+	if(mosq->tls_cafile == NULL && mosq->tls_capath == NULL){
+		return MOSQ_ERR_SUCCESS;
+	}
+#ifndef WITH_BROKER
+	if(mosq->port == 0){
+		/* No hostname verification for unix sockets */
+		return MOSQ_ERR_SUCCESS;
+	}
+#endif
 #ifdef WIN32
 	ipv6_ok = InetPton(AF_INET6, hostname, &ipv6_addr);
 	ipv4_ok = InetPton(AF_INET, hostname, &ipv4_addr);
@@ -147,46 +73,16 @@ int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname)
 	ipv4_ok = inet_pton(AF_INET, hostname, &ipv4_addr);
 #endif
 
-	san = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-	if(san){
-		for(i=0; i<sk_GENERAL_NAME_num(san); i++){
-			nval = sk_GENERAL_NAME_value(san, i);
-			if(nval->type == GEN_DNS){
-				data = ASN1_STRING_get0_data(nval->d.dNSName);
-				if(data && !mosquitto__cmp_hostname_wildcard((char *)data, hostname)){
-					sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
-					return 1;
-				}
-				have_san_dns = true;
-			}else if(nval->type == GEN_IPADD){
-				data = ASN1_STRING_get0_data(nval->d.iPAddress);
-				if(nval->d.iPAddress->length == 4 && ipv4_ok){
-					if(!memcmp(ipv4_addr, data, 4)){
-						sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
-						return 1;
-					}
-				}else if(nval->d.iPAddress->length == 16 && ipv6_ok){
-					if(!memcmp(ipv6_addr, data, 16)){
-						sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
-						return 1;
-					}
-				}
-			}
-		}
-		sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
-		if(have_san_dns){
-			/* Only check CN if subjectAltName DNS entry does not exist. */
-			return 0;
-		}
+	X509_VERIFY_PARAM *param = SSL_get0_param(mosq->ssl);
+	if(ipv4_ok || ipv6_ok){
+		rc = X509_VERIFY_PARAM_set1_ip_asc(param, hostname);
+	}else{
+		rc = X509_VERIFY_PARAM_set1_host(param, hostname, 0);
 	}
-
-	subj = X509_get_subject_name(cert);
-	if(X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0){
-		name[sizeof(name) - 1] = '\0';
-		if (!mosquitto__cmp_hostname_wildcard(name, hostname)) return 1;
+	if(rc == 1){
+		return MOSQ_ERR_SUCCESS;
+	}else{
+		return MOSQ_ERR_TLS;
 	}
-	return 0;
 }
-
 #endif
-
diff --git a/lib/tls_mosq.h b/lib/tls_mosq.h
index f8734042c6..220a6abd85 100644
--- a/lib/tls_mosq.h
+++ b/lib/tls_mosq.h
@@ -29,9 +29,10 @@ SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 
 #include <openssl/ssl.h>
 #include <openssl/engine.h>
+#include "mosquitto.h"
 
 int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx);
-int mosquitto__verify_certificate_hostname(X509 *cert, const char *hostname);
+int tls__set_verify_hostname(struct mosquitto *mosq, const char *hostname);
 
 #endif /* WITH_TLS */
 
