changeset 16159:f4bac0352464

lib-ssl-iostream: Added support for TLS SNI, which caused some API changes.
author Timo Sirainen <tss@iki.fi>
date Thu, 04 Apr 2013 17:39:17 +0300
parents 52efc1740e15
children 41c10ddda867
files src/doveadm/server-connection.c src/lib-http/http-client-connection.c src/lib-imap-client/imapc-connection.c src/lib-master/master-service-ssl.c src/lib-ssl-iostream/iostream-openssl-context.c src/lib-ssl-iostream/iostream-openssl.c src/lib-ssl-iostream/iostream-openssl.h src/lib-ssl-iostream/iostream-ssl-private.h src/lib-ssl-iostream/iostream-ssl.c src/lib-ssl-iostream/iostream-ssl.h src/lib-storage/index/pop3c/pop3c-client.c
diffstat 11 files changed, 125 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/server-connection.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/doveadm/server-connection.c	Thu Apr 04 17:39:17 2013 +0300
@@ -358,9 +358,10 @@
 	ssl_set.require_valid_cert = TRUE;
 	ssl_set.verbose_invalid_cert = TRUE;
 
-	if (io_stream_create_ssl(conn->server->ssl_ctx, "doveadm", &ssl_set,
-				 &conn->input, &conn->output,
-				 &conn->ssl_iostream, &error) < 0) {
+	if (io_stream_create_ssl_client(conn->server->ssl_ctx,
+					conn->server->name, &ssl_set,
+					&conn->input, &conn->output,
+					&conn->ssl_iostream, &error) < 0) {
 		i_error("Couldn't initialize SSL client: %s", error);
 		return -1;
 	}
--- a/src/lib-http/http-client-connection.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-http/http-client-connection.c	Thu Apr 04 17:39:17 2013 +0300
@@ -667,7 +667,7 @@
 				const char **error_r)
 {
 	struct ssl_iostream_settings ssl_set;
-	const char *source, *error;
+	const char *error;
 
 	i_assert(conn->client->ssl_ctx != NULL);
 
@@ -681,11 +681,10 @@
 	if (conn->client->set.debug)
 		http_client_connection_debug(conn, "Starting SSL handshake");
 
-	source = t_strdup_printf
-		("connection %s: ", http_client_connection_label(conn));
-	if (io_stream_create_ssl(conn->client->ssl_ctx, source, &ssl_set,
-				 &conn->conn.input, &conn->conn.output,
-				 &conn->ssl_iostream, &error) < 0) {
+	if (io_stream_create_ssl_client(conn->client->ssl_ctx,
+					conn->peer->addr.https_name, &ssl_set,
+					&conn->conn.input, &conn->conn.output,
+					&conn->ssl_iostream, &error) < 0) {
 		*error_r = t_strdup_printf(
 			"Couldn't initialize SSL client for %s: %s",
 			conn->conn.name, error);
--- a/src/lib-imap-client/imapc-connection.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Thu Apr 04 17:39:17 2013 +0300
@@ -1158,7 +1158,7 @@
 {
 	struct ssl_iostream_settings ssl_set;
 	struct stat st;
-	const char *source, *error;
+	const char *error;
 
 	if (conn->client->ssl_ctx == NULL) {
 		i_error("imapc(%s): No SSL context", conn->name);
@@ -1185,10 +1185,10 @@
 		conn->output = conn->raw_output;
 	}
 
-	source = t_strdup_printf("imapc(%s): ", conn->name);
-	if (io_stream_create_ssl(conn->client->ssl_ctx, source, &ssl_set,
-				 &conn->input, &conn->output,
-				 &conn->ssl_iostream, &error) < 0) {
+	if (io_stream_create_ssl_client(conn->client->ssl_ctx,
+					conn->client->set.host,
+					&ssl_set, &conn->input, &conn->output,
+					&conn->ssl_iostream, &error) < 0) {
 		i_error("imapc(%s): Couldn't initialize SSL client: %s",
 			conn->name, error);
 		return -1;
--- a/src/lib-master/master-service-ssl.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-master/master-service-ssl.c	Thu Apr 04 17:39:17 2013 +0300
@@ -82,8 +82,8 @@
 	ssl_set.verbose = set->verbose_ssl;
 	ssl_set.verify_remote_cert = set->ssl_verify_client_cert;
 
-	return io_stream_create_ssl(service->ssl_ctx, service->name, &ssl_set,
-				    input, output, ssl_iostream_r, error_r);
+	return io_stream_create_ssl_server(service->ssl_ctx, &ssl_set,
+					   input, output, ssl_iostream_r, error_r);
 }
 
 bool master_service_ssl_is_enabled(struct master_service *service)
--- a/src/lib-ssl-iostream/iostream-openssl-context.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl-context.c	Thu Apr 04 17:39:17 2013 +0300
@@ -291,6 +291,25 @@
 	return new_set;
 }
 
+#ifdef HAVE_SSL_GET_SERVERNAME
+static int ssl_servername_callback(SSL *ssl, int *al ATTR_UNUSED,
+				   void *context ATTR_UNUSED)
+{
+	struct ssl_iostream *ssl_io;
+	const char *host;
+
+	ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
+	host = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+	if (SSL_get_servername_type(ssl) != -1) {
+		i_free(ssl_io->host);
+		ssl_io->host = i_strdup(host);
+	} else if (ssl_io->verbose) {
+		i_debug("SSL_get_servername() failed");
+	}
+	return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
 static int
 ssl_iostream_context_set(struct ssl_iostream_context *ctx,
 			 const struct ssl_iostream_settings *set,
@@ -355,6 +374,15 @@
 			return -1;
 		}
 	}
+#ifdef HAVE_SSL_GET_SERVERNAME
+	if (!ctx->client_ctx) {
+		if (SSL_CTX_set_tlsext_servername_callback(ctx->ssl_ctx,
+					ssl_servername_callback) != 1) {
+			if (set->verbose)
+				i_debug("OpenSSL library doesn't support SNI");
+		}
+	}
+#endif
 	return 0;
 }
 
--- a/src/lib-ssl-iostream/iostream-openssl.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.c	Thu Apr 04 17:39:17 2013 +0300
@@ -15,16 +15,16 @@
 
 	ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
 	if ((where & SSL_CB_ALERT) != 0) {
-		i_warning("%s: SSL alert: where=0x%x, ret=%d: %s %s",
-			  ssl_io->source, where, ret,
+		i_warning("%sSSL alert: where=0x%x, ret=%d: %s %s",
+			  ssl_io->log_prefix, where, ret,
 			  SSL_alert_type_string_long(ret),
 			  SSL_alert_desc_string_long(ret));
 	} else if (ret == 0) {
-		i_warning("%s: SSL failed: where=0x%x: %s",
-			  ssl_io->source, where, SSL_state_string_long(ssl));
+		i_warning("%sSSL failed: where=0x%x: %s",
+			  ssl_io->log_prefix, where, SSL_state_string_long(ssl));
 	} else {
-		i_debug("%s: SSL: where=0x%x, ret=%d: %s",
-			ssl_io->source, where, ret,
+		i_debug("%sSSL: where=0x%x, ret=%d: %s",
+			ssl_io->log_prefix, where, ret,
 			SSL_state_string_long(ssl));
 	}
 }
@@ -128,7 +128,7 @@
 	if (set->verbose)
 		SSL_set_info_callback(ssl_io->ssl, openssl_info_callback);
 
-	if (set->cipher_list != NULL &&
+       if (set->cipher_list != NULL &&
 	    strcmp(ctx_set->cipher_list, set->cipher_list) != 0) {
 		if (!SSL_set_cipher_list(ssl_io->ssl, set->cipher_list)) {
 			*error_r = t_strdup_printf(
@@ -179,7 +179,7 @@
 }
 
 static int
-openssl_iostream_create(struct ssl_iostream_context *ctx, const char *source,
+openssl_iostream_create(struct ssl_iostream_context *ctx, const char *host,
 			const struct ssl_iostream_settings *set,
 			struct istream **input, struct ostream **output,
 			struct ssl_iostream **iostream_r,
@@ -215,10 +215,15 @@
 	ssl_io->bio_ext = bio_ext;
 	ssl_io->plain_input = *input;
 	ssl_io->plain_output = *output;
-	ssl_io->source = i_strdup(source);
+	ssl_io->host = i_strdup(host);
+	ssl_io->log_prefix = host == NULL ? i_strdup("") :
+		i_strdup_printf("%s: ", host);
 	/* bio_int will be freed by SSL_free() */
 	SSL_set_bio(ssl_io->ssl, bio_int, bio_int);
         SSL_set_ex_data(ssl_io->ssl, dovecot_ssl_extdata_index, ssl_io);
+#ifdef HAVE_SSL_GET_SERVERNAME
+	SSL_set_tlsext_host_name(ssl_io->ssl, host);
+#endif
 
 	if (openssl_iostream_set(ssl_io, set, error_r) < 0) {
 		openssl_iostream_free(ssl_io);
@@ -249,7 +254,8 @@
 	BIO_free(ssl_io->bio_ext);
 	SSL_free(ssl_io->ssl);
 	i_free(ssl_io->last_error);
-	i_free(ssl_io->source);
+	i_free(ssl_io->host);
+	i_free(ssl_io->log_prefix);
 	i_free(ssl_io);
 }
 
@@ -566,6 +572,13 @@
 	ssl_io->handshake_context = context;
 }
 
+static void openssl_iostream_set_log_prefix(struct ssl_iostream *ssl_io,
+					    const char *prefix)
+{
+	i_free(ssl_io->log_prefix);
+	ssl_io->log_prefix = i_strdup(prefix);
+}
+
 static bool openssl_iostream_is_handshaked(const struct ssl_iostream *ssl_io)
 {
 	return ssl_io->handshaked;
@@ -617,6 +630,11 @@
 	return *name == '\0' ? NULL : name;
 }
 
+static const char *openssl_iostream_get_server_name(struct ssl_iostream *ssl_io)
+{
+	return ssl_io->host;
+}
+
 static const char *
 openssl_iostream_get_security_string(struct ssl_iostream *ssl_io)
 {
@@ -666,11 +684,13 @@
 	openssl_iostream_handshake,
 	openssl_iostream_set_handshake_callback,
 
+	openssl_iostream_set_log_prefix,
 	openssl_iostream_is_handshaked,
 	openssl_iostream_has_valid_client_cert,
 	openssl_iostream_has_broken_client_cert,
 	openssl_iostream_cert_match_name,
 	openssl_iostream_get_peer_name,
+	openssl_iostream_get_server_name,
 	openssl_iostream_get_security_string,
 	openssl_iostream_get_last_error
 };
--- a/src/lib-ssl-iostream/iostream-openssl.h	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.h	Thu Apr 04 17:39:17 2013 +0300
@@ -21,8 +21,6 @@
 	int refcount;
 	struct ssl_iostream_context *ctx;
 
-	const struct ssl_iostream_settings *set;
-
 	SSL *ssl;
 	BIO *bio_ext;
 
@@ -30,8 +28,9 @@
 	struct ostream *plain_output;
 	struct ostream *ssl_output;
 
-	char *source;
+	char *host;
 	char *last_error;
+	char *log_prefix;
 	int plain_stream_errno;
 
 	/* copied settings */
--- a/src/lib-ssl-iostream/iostream-ssl-private.h	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-ssl-private.h	Thu Apr 04 17:39:17 2013 +0300
@@ -16,7 +16,7 @@
 	int (*context_import_params)(struct ssl_iostream_context *ctx,
 				     const buffer_t *input);
 
-	int (*create)(struct ssl_iostream_context *ctx, const char *source,
+	int (*create)(struct ssl_iostream_context *ctx, const char *host,
 		      const struct ssl_iostream_settings *set,
 		      struct istream **input, struct ostream **output,
 		      struct ssl_iostream **iostream_r, const char **error_r);
@@ -28,11 +28,13 @@
 				       ssl_iostream_handshake_callback_t *callback,
 				       void *context);
 
+	void (*set_log_prefix)(struct ssl_iostream *ssl_io, const char *prefix);
 	bool (*is_handshaked)(const struct ssl_iostream *ssl_io);
 	bool (*has_valid_client_cert)(const struct ssl_iostream *ssl_io);
 	bool (*has_broken_client_cert)(struct ssl_iostream *ssl_io);
 	int (*cert_match_name)(struct ssl_iostream *ssl_io, const char *name);
 	const char *(*get_peer_name)(struct ssl_iostream *ssl_io);
+	const char *(*get_server_name)(struct ssl_iostream *ssl_io);
 	const char *(*get_security_string)(struct ssl_iostream *ssl_io);
 	const char *(*get_last_error)(struct ssl_iostream *ssl_io);
 };
--- a/src/lib-ssl-iostream/iostream-ssl.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-ssl.c	Thu Apr 04 17:39:17 2013 +0300
@@ -92,13 +92,23 @@
 	return ssl_vfuncs->context_import_params(ctx, input);
 }
 
-int io_stream_create_ssl(struct ssl_iostream_context *ctx, const char *source,
-			 const struct ssl_iostream_settings *set,
-			 struct istream **input, struct ostream **output,
-			 struct ssl_iostream **iostream_r,
-			 const char **error_r)
+int io_stream_create_ssl_client(struct ssl_iostream_context *ctx, const char *host,
+				const struct ssl_iostream_settings *set,
+				struct istream **input, struct ostream **output,
+				struct ssl_iostream **iostream_r,
+				const char **error_r)
 {
-	return ssl_vfuncs->create(ctx, source, set, input, output,
+	return ssl_vfuncs->create(ctx, host, set, input, output,
+				  iostream_r, error_r);
+}
+
+int io_stream_create_ssl_server(struct ssl_iostream_context *ctx,
+				const struct ssl_iostream_settings *set,
+				struct istream **input, struct ostream **output,
+				struct ssl_iostream **iostream_r,
+				const char **error_r)
+{
+	return ssl_vfuncs->create(ctx, NULL, set, input, output,
 				  iostream_r, error_r);
 }
 
@@ -118,6 +128,12 @@
 	ssl_vfuncs->destroy(ssl_io);
 }
 
+void ssl_iostream_set_log_prefix(struct ssl_iostream *ssl_io,
+				 const char *prefix)
+{
+	ssl_vfuncs->set_log_prefix(ssl_io, prefix);
+}
+
 int ssl_iostream_handshake(struct ssl_iostream *ssl_io)
 {
 	return ssl_vfuncs->handshake(ssl_io);
@@ -155,6 +171,11 @@
 	return ssl_vfuncs->get_peer_name(ssl_io);
 }
 
+const char *ssl_iostream_get_server_name(struct ssl_iostream *ssl_io)
+{
+	return ssl_vfuncs->get_server_name(ssl_io);
+}
+
 const char *ssl_iostream_get_security_string(struct ssl_iostream *ssl_io)
 {
 	return ssl_vfuncs->get_security_string(ssl_io);
--- a/src/lib-ssl-iostream/iostream-ssl.h	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-ssl.h	Thu Apr 04 17:39:17 2013 +0300
@@ -24,16 +24,25 @@
 typedef int
 ssl_iostream_handshake_callback_t(const char **error_r, void *context);
 
-int io_stream_create_ssl(struct ssl_iostream_context *ctx, const char *source,
-			 const struct ssl_iostream_settings *set,
-			 struct istream **input, struct ostream **output,
-			 struct ssl_iostream **iostream_r,
-			 const char **error_r);
+int io_stream_create_ssl_client(struct ssl_iostream_context *ctx, const char *host,
+				const struct ssl_iostream_settings *set,
+				struct istream **input, struct ostream **output,
+				struct ssl_iostream **iostream_r,
+				const char **error_r);
+int io_stream_create_ssl_server(struct ssl_iostream_context *ctx,
+				const struct ssl_iostream_settings *set,
+				struct istream **input, struct ostream **output,
+				struct ssl_iostream **iostream_r,
+				const char **error_r);
 /* returned input and output streams must also be unreferenced */
 void ssl_iostream_unref(struct ssl_iostream **ssl_io);
 /* shutdown SSL connection and unreference ssl iostream */
 void ssl_iostream_destroy(struct ssl_iostream **ssl_io);
 
+/* If verbose logging is enabled, use the specified log prefix */
+void ssl_iostream_set_log_prefix(struct ssl_iostream *ssl_io,
+				 const char *prefix);
+
 int ssl_iostream_handshake(struct ssl_iostream *ssl_io);
 void ssl_iostream_set_handshake_callback(struct ssl_iostream *ssl_io,
 					 ssl_iostream_handshake_callback_t *callback,
@@ -44,6 +53,7 @@
 bool ssl_iostream_has_broken_client_cert(struct ssl_iostream *ssl_io);
 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);
 const char *ssl_iostream_get_security_string(struct ssl_iostream *ssl_io);
 const char *ssl_iostream_get_last_error(struct ssl_iostream *ssl_io);
 
--- a/src/lib-storage/index/pop3c/pop3c-client.c	Thu Apr 04 17:34:23 2013 +0300
+++ b/src/lib-storage/index/pop3c/pop3c-client.c	Thu Apr 04 17:39:17 2013 +0300
@@ -441,7 +441,7 @@
 {
 	struct ssl_iostream_settings ssl_set;
 	struct stat st;
-	const char *source, *error;
+	const char *error;
 
 	if (client->ssl_ctx == NULL) {
 		i_error("pop3c(%s): No SSL context", client->set.host);
@@ -468,10 +468,9 @@
 		client->output = client->raw_output;
 	}
 
-	source = t_strdup_printf("pop3c(%s): ", client->set.host);
-	if (io_stream_create_ssl(client->ssl_ctx, source, &ssl_set,
-				 &client->input, &client->output,
-				 &client->ssl_iostream, &error) < 0) {
+	if (io_stream_create_ssl_client(client->ssl_ctx, client->set.host,
+					&ssl_set, &client->input, &client->output,
+					&client->ssl_iostream, &error) < 0) {
 		i_error("pop3c(%s): Couldn't initialize SSL client: %s",
 			client->set.host, error);
 		return -1;