diff -up dovecot-1.0.7/dovecot-example.conf.sslprot dovecot-1.0.7/dovecot-example.conf --- dovecot-1.0.7/dovecot-example.conf.sslprot 2014-10-20 00:09:29.678506343 +0200 +++ dovecot-1.0.7/dovecot-example.conf 2014-10-20 00:09:29.840503239 +0200 @@ -111,6 +111,9 @@ # entirely. #ssl_parameters_regenerate = 168 +# SSL protocols to use +#ssl_protocols = !SSLv2 !SSLv3 + # SSL ciphers to use #ssl_cipher_list = ALL:!LOW diff -up dovecot-1.0.7/src/login-common/ssl-proxy-openssl.c.sslprot dovecot-1.0.7/src/login-common/ssl-proxy-openssl.c --- dovecot-1.0.7/src/login-common/ssl-proxy-openssl.c.sslprot 2007-10-28 02:09:24.000000000 +0200 +++ dovecot-1.0.7/src/login-common/ssl-proxy-openssl.c 2014-10-20 00:09:29.852503009 +0200 @@ -667,9 +667,62 @@ unsigned int ssl_proxy_get_count(void) return ssl_proxies == NULL ? 0 : hash_size(ssl_proxies); } +enum { + DOVECOT_SSL_PROTO_SSLv2 = 0x01, + DOVECOT_SSL_PROTO_SSLv3 = 0x02, + DOVECOT_SSL_PROTO_TLSv1 = 0x04, + DOVECOT_SSL_PROTO_ALL = 0x07 +}; + +static void +ssl_proxy_ctx_set_protocols(/*struct ssl_server_context *ssl_ctx,*/ + const char *protocols) +{ + const char *const *tmp; + int proto, op = 0, include = 0, exclude = 0; + bool neg; + + tmp = t_strsplit_spaces(protocols, " "); + for (; *tmp != NULL; tmp++) { + const char *name = *tmp; + + if (*name != '!') + neg = FALSE; + else { + name++; + neg = TRUE; + } + if (strcasecmp(name, SSL_TXT_SSLV2) == 0) + proto = DOVECOT_SSL_PROTO_SSLv2; + else if (strcasecmp(name, SSL_TXT_SSLV3) == 0) + proto = DOVECOT_SSL_PROTO_SSLv3; + else if (strcasecmp(name, SSL_TXT_TLSV1) == 0) + proto = DOVECOT_SSL_PROTO_TLSv1; + else { + i_fatal("Invalid ssl_protocols setting: " + "Unknown protocol '%s'", name); + } + if (neg) + exclude |= proto; + else + include |= proto; + } + if (include != 0) { + /* exclude everything, except those that are included + (and let excludes still override those) */ + exclude |= DOVECOT_SSL_PROTO_ALL & ~include; + } + if ((exclude & DOVECOT_SSL_PROTO_SSLv2) != 0) op |= SSL_OP_NO_SSLv2; + if ((exclude & DOVECOT_SSL_PROTO_SSLv3) != 0) op |= SSL_OP_NO_SSLv3; + if ((exclude & DOVECOT_SSL_PROTO_TLSv1) != 0) op |= SSL_OP_NO_TLSv1; + SSL_CTX_set_options(ssl_ctx, op); +} + + + void ssl_proxy_init(void) { - const char *cafile, *certfile, *keyfile, *cipher_list; + const char *cafile, *certfile, *keyfile, *cipher_list, *protocols; char *password; unsigned char buf; @@ -694,6 +747,8 @@ void ssl_proxy_init(void) if ((ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) i_fatal("SSL_CTX_new() failed"); + protocols = getenv("SSL_PROTOCOLS"); + SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL); cipher_list = getenv("SSL_CIPHER_LIST"); @@ -704,6 +759,8 @@ void ssl_proxy_init(void) cipher_list, ssl_last_error()); } + ssl_proxy_ctx_set_protocols(protocols); + if (cafile != NULL) { if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, NULL) != 1) { i_fatal("Can't load CA file %s: %s", diff -up dovecot-1.0.7/src/master/login-process.c.sslprot dovecot-1.0.7/src/master/login-process.c --- dovecot-1.0.7/src/master/login-process.c.sslprot 2014-10-20 00:09:29.639507090 +0200 +++ dovecot-1.0.7/src/master/login-process.c 2014-10-20 00:09:29.856502932 +0200 @@ -546,6 +546,10 @@ static void login_process_init_env(struc env_put(t_strconcat("SSL_CIPHER_LIST=", set->ssl_cipher_list, NULL)); } + if (*set->ssl_protocols != '\0') { + env_put(t_strconcat("SSL_PROTOCOLS=", + set->ssl_protocols, NULL)); + } if (set->ssl_verify_client_cert) env_put("SSL_VERIFY_CLIENT_CERT=1"); } diff -up dovecot-1.0.7/src/master/master-settings.c.sslprot dovecot-1.0.7/src/master/master-settings.c --- dovecot-1.0.7/src/master/master-settings.c.sslprot 2014-10-20 00:09:29.643507014 +0200 +++ dovecot-1.0.7/src/master/master-settings.c 2014-10-20 00:09:29.860502855 +0200 @@ -173,6 +173,7 @@ struct settings default_settings = { MEMBER(ssl_key_password) "", MEMBER(ssl_parameters_regenerate) 168, MEMBER(ssl_cipher_list) "", + MEMBER(ssl_protocols) "!SSLv2 !SSLv3", MEMBER(ssl_verify_client_cert) FALSE, MEMBER(disable_plaintext_auth) FALSE, MEMBER(verbose_ssl) FALSE, diff -up dovecot-1.0.7/src/master/master-settings-defs.c.sslprot dovecot-1.0.7/src/master/master-settings-defs.c --- dovecot-1.0.7/src/master/master-settings-defs.c.sslprot 2014-10-20 00:11:10.593572486 +0200 +++ dovecot-1.0.7/src/master/master-settings-defs.c 2014-10-20 00:11:10.645571490 +0200 @@ -23,6 +23,7 @@ static struct setting_def setting_defs[] DEF(SET_STR, ssl_key_password), DEF(SET_INT, ssl_parameters_regenerate), DEF(SET_STR, ssl_cipher_list), + DEF(SET_STR, ssl_protocols), DEF(SET_BOOL, ssl_verify_client_cert), DEF(SET_BOOL, disable_plaintext_auth), DEF(SET_BOOL, verbose_ssl), diff -up dovecot-1.0.7/src/master/master-settings.h.sslprot dovecot-1.0.7/src/master/master-settings.h --- dovecot-1.0.7/src/master/master-settings.h.sslprot 2014-10-20 00:09:29.777504446 +0200 +++ dovecot-1.0.7/src/master/master-settings.h 2014-10-20 00:09:29.864502779 +0200 @@ -33,6 +33,7 @@ struct settings { const char *ssl_key_password; unsigned int ssl_parameters_regenerate; const char *ssl_cipher_list; + const char *ssl_protocols; bool ssl_verify_client_cert; bool disable_plaintext_auth; bool verbose_ssl;