Dear all,

I tried to do a backport of 'ssl_prefer_server_ciphers'
(http://hg.dovecot.org/dovecot-2.2/rev/897484f45a87/) to Dovecot 2.1
(namely the Debian version of Dovecot) and wanted to ask if there is any
chance to integrate this feature into Dovecot 2.1 'upstream' as well.
As the code structure changed quite a bit, I am not sure if my patch is
complete. I tested it with pop3s and imaps in my test environment and it
works just as expected and seemed to not have any unwanted effects.
(Dovecot code is probably the most beautiful and easy to read C code I've
seen, but there might also be some pitfalls I missed.)

best regards,
    Adi Kriegisch

PS: I need that feature to enable PFS while allowing Outlook to still
connect and the others not to fall back to a different cipher; I was
unable to find a PFS cipher that is supported by Outlook and OpenSSL.
Description: backport 'ssl_prefer_server_ciphers' option
 This patch is a backport of the ssl_prefer_server_ciphers feature of
 newer versions of Dovecot (introduced in dovecot-2.2).
 See http://hg.dovecot.org/dovecot-2.2/rev/897484f45a87/ for the original
 implementation.

--- a/src/config/all-settings.c
+++ b/src/config/all-settings.c
@@ -1224,6 +1224,7 @@ struct login_settings {
 	bool auth_ssl_require_client_cert;
 	bool auth_ssl_username_from_cert;
 	bool verbose_ssl;
+	bool ssl_prefer_server_ciphers;
 
 	bool disable_plaintext_auth;
 	bool auth_verbose;
@@ -2527,6 +2528,7 @@ static const struct setting_define login
 	DEF(SET_BOOL, auth_ssl_require_client_cert),
 	DEF(SET_BOOL, auth_ssl_username_from_cert),
 	DEF(SET_BOOL, verbose_ssl),
+	DEF(SET_BOOL, ssl_prefer_server_ciphers),
 
 	DEF(SET_BOOL, disable_plaintext_auth),
 	DEF(SET_BOOL, auth_verbose),
@@ -2561,6 +2563,7 @@ static const struct login_settings login
 	.auth_ssl_require_client_cert = FALSE,
 	.auth_ssl_username_from_cert = FALSE,
 	.verbose_ssl = FALSE,
+	.ssl_prefer_server_ciphers = FALSE,
 
 	.disable_plaintext_auth = TRUE,
 	.auth_verbose = FALSE,
--- a/src/lib-ssl-iostream/iostream-openssl-context.c
+++ b/src/lib-ssl-iostream/iostream-openssl-context.c
@@ -302,6 +302,10 @@ ssl_iostream_context_set(struct ssl_iost
 			ssl_iostream_error());
 		return -1;
 	}
+	if (set->prefer_server_ciphers) {
+			SSL_CTX_set_options(ctx->ssl_ctx,
+								SSL_OP_CIPHER_SERVER_PREFERENCE);
+	}
 
 	if (set->cert != NULL &&
 	    ssl_ctx_use_certificate_chain(ctx->ssl_ctx, set->cert) < 0) {
--- a/src/lib-ssl-iostream/iostream-ssl.h
+++ b/src/lib-ssl-iostream/iostream-ssl.h
@@ -16,6 +16,7 @@ struct ssl_iostream_settings {
 	bool verbose, verbose_invalid_cert;
 	bool verify_remote_cert;
 	bool require_valid_cert;
+	bool prefer_server_ciphers;
 };
 
 int io_stream_create_ssl(struct ssl_iostream_context *ctx, const char *source,
--- a/src/lib-ssl-iostream/iostream-openssl.c
+++ b/src/lib-ssl-iostream/iostream-openssl.c
@@ -135,6 +135,8 @@ ssl_iostream_set(struct ssl_iostream *ss
 		return -1;
 
 	}
+	if (set->prefer_server_ciphers)
+		SSL_set_options(ssl_io->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
 	if (set->cert != NULL && strcmp(ctx_set->cert, set->cert) != 0) {
 		if (ssl_iostream_use_certificate(ssl_io, set->cert) < 0)
 			return -1;
--- a/src/login-common/ssl-proxy-openssl.c
+++ b/src/login-common/ssl-proxy-openssl.c
@@ -93,6 +93,7 @@ struct ssl_server_context {
 	const char *cipher_list;
 	const char *protocols;
 	bool verify_client_cert;
+	bool prefer_server_ciphers;
 };
 
 static int extdata_index;
@@ -617,6 +618,7 @@ ssl_server_context_get(const struct logi
 	lookup_ctx.cipher_list = set->ssl_cipher_list;
 	lookup_ctx.protocols = set->ssl_protocols;
 	lookup_ctx.verify_client_cert = set->ssl_verify_client_cert;
+	lookup_ctx.prefer_server_ciphers = set->ssl_prefer_server_ciphers;
 
 	ctx = hash_table_lookup(ssl_servers, &lookup_ctx);
 	if (ctx == NULL)
@@ -1217,6 +1219,7 @@ ssl_server_context_init(const struct log
 	ctx->cipher_list = p_strdup(pool, set->ssl_cipher_list);
 	ctx->protocols = p_strdup(pool, set->ssl_protocols);
 	ctx->verify_client_cert = set->ssl_verify_client_cert;
+	ctx->prefer_server_ciphers = set->ssl_prefer_server_ciphers;
 
 	ctx->ctx = ssl_ctx = SSL_CTX_new(SSLv23_server_method());
 	if (ssl_ctx == NULL)
@@ -1227,6 +1230,8 @@ ssl_server_context_init(const struct log
 		i_fatal("Can't set cipher list to '%s': %s",
 			ctx->cipher_list, ssl_last_error());
 	}
+	if (ctx->prefer_server_ciphers)
+		SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
 	ssl_proxy_ctx_set_protocols(ctx, ctx->protocols);
 
 	if (ssl_proxy_ctx_use_certificate_chain(ctx->ctx, ctx->cert) != 1) {
--- a/src/login-common/login-settings.c
+++ b/src/login-common/login-settings.c
@@ -42,6 +42,7 @@ static const struct setting_define login
 	DEF(SET_BOOL, auth_ssl_require_client_cert),
 	DEF(SET_BOOL, auth_ssl_username_from_cert),
 	DEF(SET_BOOL, verbose_ssl),
+	DEF(SET_BOOL, ssl_prefer_server_ciphers),
 
 	DEF(SET_BOOL, disable_plaintext_auth),
 	DEF(SET_BOOL, auth_verbose),
@@ -77,6 +78,7 @@ static const struct login_settings login
 	.auth_ssl_require_client_cert = FALSE,
 	.auth_ssl_username_from_cert = FALSE,
 	.verbose_ssl = FALSE,
+	.ssl_prefer_server_ciphers = FALSE,
 
 	.disable_plaintext_auth = TRUE,
 	.auth_verbose = FALSE,
--- a/src/login-common/login-settings.h
+++ b/src/login-common/login-settings.h
@@ -24,6 +24,7 @@ struct login_settings {
 	bool auth_ssl_require_client_cert;
 	bool auth_ssl_username_from_cert;
 	bool verbose_ssl;
+	bool ssl_prefer_server_ciphers;
 
 	bool disable_plaintext_auth;
 	bool auth_verbose;
--- a/doc/example-config/conf.d/10-ssl.conf
+++ b/doc/example-config/conf.d/10-ssl.conf
@@ -46,5 +46,8 @@ ssl_key = </etc/dovecot/private/dovecot.
 # SSL ciphers to use
 #ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
 
+# Prefer the server's order of ciphers over client
+#ssl_prefer_server_ciphers = no
+
 # SSL crypto device to use, for valid values run "openssl engine"
 #ssl_crypto_device =

Reply via email to