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 =