dovecot-2.2: lib-ssl-iostream: Simplified certificate validation...

dovecot at dovecot.org dovecot at dovecot.org
Thu Apr 4 18:10:12 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/ef939a32de27
changeset: 16161:ef939a32de27
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Apr 04 18:10:04 2013 +0300
description:
lib-ssl-iostream: Simplified certificate validation. Also give better error messages.

diffstat:

 src/doveadm/server-connection.c            |  21 ++---------
 src/lib-http/http-client-connection.c      |  22 +++--------
 src/lib-imap-client/imapc-connection.c     |  30 +++++++--------
 src/lib-ssl-iostream/iostream-openssl.c    |  55 ++++++++++++++---------------
 src/lib-ssl-iostream/iostream-ssl.c        |  21 +++++++++++
 src/lib-ssl-iostream/iostream-ssl.h        |   2 +
 src/lib-storage/index/pop3c/pop3c-client.c |  30 +++++++--------
 7 files changed, 89 insertions(+), 92 deletions(-)

diffs (truncated from 311 to 300 lines):

diff -r 41c10ddda867 -r ef939a32de27 src/doveadm/server-connection.c
--- a/src/doveadm/server-connection.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/doveadm/server-connection.c	Thu Apr 04 18:10:04 2013 +0300
@@ -325,24 +325,11 @@
 	if (p != NULL)
 		host = t_strdup_until(host, p);
 
-	if (!ssl_iostream_has_valid_client_cert(conn->ssl_iostream)) {
-		if (!ssl_iostream_has_broken_client_cert(conn->ssl_iostream))
-			*error_r = "SSL certificate not received";
-		else
-			*error_r = "Received invalid SSL certificate";
+	if (ssl_iostream_check_cert_validity(conn->ssl_iostream, host, error_r) < 0)
 		return -1;
-	} else if (ssl_iostream_cert_match_name(conn->ssl_iostream, host) < 0) {
-		*error_r = t_strdup_printf(
-			"SSL certificate doesn't match expected host name %s",
-			host);
-		return -1;
-	} else {
-		if (doveadm_debug) {
-			i_debug("%s: SSL handshake successful",
-				conn->server->name);
-		}
-		return 0;
-	}
+	if (doveadm_debug)
+		i_debug("%s: SSL handshake successful", conn->server->name);
+	return 0;
 }
 
 static int server_connection_init_ssl(struct server_connection *conn)
diff -r 41c10ddda867 -r ef939a32de27 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-http/http-client-connection.c	Thu Apr 04 18:10:04 2013 +0300
@@ -640,26 +640,18 @@
 http_client_connection_ssl_handshaked(const char **error_r, void *context)
 {
 	struct http_client_connection *conn = context;
-	const char *host = conn->peer->addr.https_name;
+	const char *error, *host = conn->peer->addr.https_name;
 
-	if (conn->client->set.ssl_allow_invalid_cert) {
-		/* skip certificate checks */
+	if (ssl_iostream_check_cert_validity(conn->ssl_iostream, host, &error) == 0)
 		http_client_connection_debug(conn, "SSL handshake successful");
-		return 0;
-	} else if (!ssl_iostream_has_valid_client_cert(conn->ssl_iostream)) {
-		if (!ssl_iostream_has_broken_client_cert(conn->ssl_iostream))
-			*error_r = "SSL certificate not received";
-		else
-			*error_r = "Received invalid SSL certificate";
-		return -1;
-	} else if (ssl_iostream_cert_match_name(conn->ssl_iostream, host) == 0) {
-		http_client_connection_debug(conn, "SSL handshake successful");
-		return 0;
+	else if (conn->client->set.ssl_allow_invalid_cert) {
+		http_client_connection_debug(conn, "SSL handshake successful, "
+			"ignoring invalid certificate: %s", error);
 	} else {
-		*error_r = t_strdup_printf(
-			"SSL certificate doesn't match expected host name %s", host);
+		*error_r = error;
 		return -1;
 	}
+	return 0;
 }
 
 static int 
diff -r 41c10ddda867 -r ef939a32de27 src/lib-imap-client/imapc-connection.c
--- a/src/lib-imap-client/imapc-connection.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Thu Apr 04 18:10:04 2013 +0300
@@ -1129,29 +1129,27 @@
 static int imapc_connection_ssl_handshaked(const char **error_r, void *context)
 {
 	struct imapc_connection *conn = context;
+	const char *error;
 
-	if (!conn->client->set.ssl_verify) {
-		/* skip certificate checks */
-		return 0;
-	} else if (!ssl_iostream_has_valid_client_cert(conn->ssl_iostream)) {
-		if (!ssl_iostream_has_broken_client_cert(conn->ssl_iostream))
-			*error_r = "SSL certificate not received";
-		else
-			*error_r = "Received invalid SSL certificate";
-	} else if (ssl_iostream_cert_match_name(conn->ssl_iostream,
-						conn->client->set.host) < 0) {
-		*error_r = t_strdup_printf(
-			"SSL certificate doesn't match expected host name %s",
-			conn->client->set.host);
-	} else {
+	if (ssl_iostream_check_cert_validity(conn->ssl_iostream,
+					     conn->client->set.host, &error) == 0) {
 		if (conn->client->set.debug) {
 			i_debug("imapc(%s): SSL handshake successful",
 				conn->name);
 		}
 		return 0;
+	} else if (!conn->client->set.ssl_verify) {
+		if (conn->client->set.debug) {
+			i_debug("imapc(%s): SSL handshake successful, "
+				"ignoring invalid certificate: %s",
+				conn->name, error);
+		}
+		return 0;
+	} else {
+		conn->handshake_failed = TRUE;
+		*error_r = error;
+		return -1;
 	}
-	conn->handshake_failed = TRUE;
-	return -1;
 }
 
 static int imapc_connection_ssl_init(struct imapc_connection *conn)
diff -r 41c10ddda867 -r ef939a32de27 src/lib-ssl-iostream/iostream-openssl.c
--- a/src/lib-ssl-iostream/iostream-openssl.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.c	Thu Apr 04 18:10:04 2013 +0300
@@ -9,6 +9,13 @@
 
 static void openssl_iostream_free(struct ssl_iostream *ssl_io);
 
+static void
+openssl_iostream_set_error(struct ssl_iostream *ssl_io, const char *str)
+{
+	i_free(ssl_io->last_error);
+	ssl_io->last_error = i_strdup(str);
+}
+
 static void openssl_info_callback(const SSL *ssl, int where, int ret)
 {
 	struct ssl_iostream *ssl_io;
@@ -86,28 +93,27 @@
 	int ssl_extidx = SSL_get_ex_data_X509_STORE_CTX_idx();
 	SSL *ssl;
 	struct ssl_iostream *ssl_io;
+	char certname[1024];
+	X509_NAME *subject;
 
 	ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_extidx);
 	ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
 	ssl_io->cert_received = TRUE;
 
-	if (ssl_io->verbose ||
-	    (ssl_io->verbose_invalid_cert && !preverify_ok)) {
-		char buf[1024];
-		X509_NAME *subject;
-
-		subject = X509_get_subject_name(ctx->current_cert);
-		if (subject == NULL ||
-		    X509_NAME_oneline(subject, buf, sizeof(buf)) == NULL)
-			buf[0] = '\0';
-		else
-			buf[sizeof(buf)-1] = '\0'; /* just in case.. */
-		if (!preverify_ok) {
-			i_info("Invalid certificate: %s: %s",
-			       X509_verify_cert_error_string(ctx->error), buf);
-		} else {
-			i_info("Valid certificate: %s", buf);
-		}
+	subject = X509_get_subject_name(ctx->current_cert);
+	if (subject == NULL ||
+	    X509_NAME_oneline(subject, certname, sizeof(certname)) == NULL)
+		certname[0] = '\0';
+	else
+		certname[sizeof(certname)-1] = '\0'; /* just in case.. */
+	if (!preverify_ok) {
+		openssl_iostream_set_error(ssl_io, t_strdup_printf(
+			"Received invalid SSL certificate: %s: %s",
+			X509_verify_cert_error_string(ctx->error), certname));
+		if (ssl_io->verbose_invalid_cert)
+			i_info("%s", ssl_io->last_error);
+	} else if (ssl_io->verbose) {
+		i_info("Received valid SSL certificate: %s", certname);
 	}
 	if (!preverify_ok) {
 		ssl_io->cert_broken = TRUE;
@@ -173,7 +179,7 @@
 	}
 
 	ssl_io->verbose = set->verbose;
-	ssl_io->verbose_invalid_cert = set->verbose_invalid_cert;
+	ssl_io->verbose_invalid_cert = set->verbose_invalid_cert || set->verbose;
 	ssl_io->require_valid_cert = set->require_valid_cert;
 	return 0;
 }
@@ -422,13 +428,6 @@
 	return 1;
 }
 
-static void
-openssl_iostream_set_error(struct ssl_iostream *ssl_io, const char *str)
-{
-	i_free(ssl_io->last_error);
-	ssl_io->last_error = i_strdup(str);
-}
-
 static int
 openssl_iostream_handle_error_full(struct ssl_iostream *ssl_io, int ret,
 				   const char *func_name, bool write_error)
@@ -545,9 +544,6 @@
 	/* handshake finished */
 	(void)openssl_iostream_bio_sync(ssl_io);
 
-	i_free_and_null(ssl_io->last_error);
-	ssl_io->handshaked = TRUE;
-
 	if (ssl_io->handshake_callback != NULL) {
 		if (ssl_io->handshake_callback(&error, ssl_io->handshake_context) < 0) {
 			i_assert(error != NULL);
@@ -558,6 +554,9 @@
 			return -1;
 		}
 	}
+	i_free_and_null(ssl_io->last_error);
+	ssl_io->handshaked = TRUE;
+
 	if (ssl_io->ssl_output != NULL)
 		(void)o_stream_flush(ssl_io->ssl_output);
 	return 1;
diff -r 41c10ddda867 -r ef939a32de27 src/lib-ssl-iostream/iostream-ssl.c
--- a/src/lib-ssl-iostream/iostream-ssl.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-ssl.c	Thu Apr 04 18:10:04 2013 +0300
@@ -166,6 +166,27 @@
 	return ssl_vfuncs->cert_match_name(ssl_io, name);
 }
 
+int ssl_iostream_check_cert_validity(struct ssl_iostream *ssl_io,
+				     const char *host, const char **error_r)
+{
+	if (!ssl_iostream_has_valid_client_cert(ssl_io)) {
+		if (!ssl_iostream_has_broken_client_cert(ssl_io))
+			*error_r = "SSL certificate not received";
+		else {
+			*error_r = t_strdup(ssl_iostream_get_last_error(ssl_io));
+			if (*error_r == NULL)
+				*error_r = "Received invalid SSL certificate";
+		}
+		return -1;
+	} else if (ssl_iostream_cert_match_name(ssl_io, host) < 0) {
+		*error_r = t_strdup_printf(
+			"SSL certificate doesn't match expected host name %s",
+			host);
+		return -1;
+	}
+	return 0;
+}
+
 const char *ssl_iostream_get_peer_name(struct ssl_iostream *ssl_io)
 {
 	return ssl_vfuncs->get_peer_name(ssl_io);
diff -r 41c10ddda867 -r ef939a32de27 src/lib-ssl-iostream/iostream-ssl.h
--- a/src/lib-ssl-iostream/iostream-ssl.h	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-ssl.h	Thu Apr 04 18:10:04 2013 +0300
@@ -51,6 +51,8 @@
 bool ssl_iostream_is_handshaked(const struct ssl_iostream *ssl_io);
 bool ssl_iostream_has_valid_client_cert(const struct ssl_iostream *ssl_io);
 bool ssl_iostream_has_broken_client_cert(struct ssl_iostream *ssl_io);
+int ssl_iostream_check_cert_validity(struct ssl_iostream *ssl_io,
+				     const char *host, const char **error_r);
 int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io, const char *name);
 const char *ssl_iostream_get_peer_name(struct ssl_iostream *ssl_io);
 const char *ssl_iostream_get_server_name(struct ssl_iostream *ssl_io);
diff -r 41c10ddda867 -r ef939a32de27 src/lib-storage/index/pop3c/pop3c-client.c
--- a/src/lib-storage/index/pop3c/pop3c-client.c	Thu Apr 04 17:40:30 2013 +0300
+++ b/src/lib-storage/index/pop3c/pop3c-client.c	Thu Apr 04 18:10:04 2013 +0300
@@ -412,29 +412,27 @@
 static int pop3c_client_ssl_handshaked(const char **error_r, void *context)
 {
 	struct pop3c_client *client = context;
+	const char *error;
 
-	if (!client->set.ssl_verify) {
-		/* skip certificate checks */
-		return 0;
-	} else if (!ssl_iostream_has_valid_client_cert(client->ssl_iostream)) {
-		if (!ssl_iostream_has_broken_client_cert(client->ssl_iostream))
-			*error_r = "SSL certificate not received";
-		else
-			*error_r = "Received invalid SSL certificate";
-	} else if (ssl_iostream_cert_match_name(client->ssl_iostream,
-						client->set.host) < 0) {
-		*error_r = t_strdup_printf(
-			"SSL certificate doesn't match expected host name %s",
-			client->set.host);
-	} else {
+	if (ssl_iostream_check_cert_validity(client->ssl_iostream,
+					     client->set.host, &error) == 0) {
 		if (client->set.debug) {
 			i_debug("pop3c(%s): SSL handshake successful",
 				client->set.host);
 		}
 		return 0;
+	} else if (!client->set.ssl_verify) {
+		if (client->set.debug) {
+			i_debug("pop3c(%s): SSL handshake successful, "
+				"ignoring invalid certificate: %s",
+				client->set.host, error);
+		}


More information about the dovecot-cvs mailing list