]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added ssl_protocols setting.
authorTimo Sirainen <tss@iki.fi>
Sat, 1 Oct 2011 14:09:00 +0000 (17:09 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 1 Oct 2011 14:09:00 +0000 (17:09 +0300)
doc/example-config/conf.d/10-ssl.conf
src/login-common/login-settings.c
src/login-common/login-settings.h
src/login-common/ssl-proxy-openssl.c

index d8af7958e3dc23a68ebc733fa1930f4d07cfd1d3..2c27d917d808a48f46578bdb92a2a2841023f12b 100644 (file)
@@ -37,5 +37,8 @@ ssl_key = </etc/ssl/private/dovecot.pem
 # entirely.
 #ssl_parameters_regenerate = 168
 
+# SSL protocols to use
+#ssl_protocols = !SSLv2
+
 # SSL ciphers to use
 #ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
index 1463bc4a9d35cb0295fd36453e7cf2da444c8d97..4a5228acac31acda9a390e5435ddc92827df9f98 100644 (file)
@@ -31,6 +31,7 @@ static const struct setting_define login_setting_defines[] = {
        DEF(SET_STR, ssl_key),
        DEF(SET_STR, ssl_key_password),
        DEF(SET_STR, ssl_cipher_list),
+       DEF(SET_STR, ssl_protocols),
        DEF(SET_STR, ssl_cert_username_field),
        DEF(SET_BOOL, ssl_verify_client_cert),
        DEF(SET_BOOL, auth_ssl_require_client_cert),
@@ -60,6 +61,7 @@ static const struct login_settings login_default_settings = {
        .ssl_key = "",
        .ssl_key_password = "",
        .ssl_cipher_list = "ALL:!LOW:!SSLv2:!EXP:!aNULL",
+       .ssl_protocols = "!SSLv2",
        .ssl_cert_username_field = "commonName",
        .ssl_verify_client_cert = FALSE,
        .auth_ssl_require_client_cert = FALSE,
index 1147d00a0f8d2c170326ffe8bb4f05d79f2f8299..d03658e06937bbde17d3e30bd727b82c368c7c04 100644 (file)
@@ -13,6 +13,7 @@ struct login_settings {
        const char *ssl_key;
        const char *ssl_key_password;
        const char *ssl_cipher_list;
+       const char *ssl_protocols;
        const char *ssl_cert_username_field;
        bool ssl_verify_client_cert;
        bool auth_ssl_require_client_cert;
index e39935314c44e5b7a0445e91f6b2e0c46e6f4696..fd05149c2164ca0efdeb0f34d8452355afcc47e9 100644 (file)
@@ -87,6 +87,7 @@ struct ssl_server_context {
        const char *key;
        const char *ca;
        const char *cipher_list;
+       const char *protocols;
        bool verify_client_cert;
 };
 
@@ -136,6 +137,8 @@ static int ssl_server_context_cmp(const void *p1, const void *p2)
                return 1;
        if (null_strcmp(ctx1->cipher_list, ctx2->cipher_list) != 0)
                return 1;
+       if (null_strcmp(ctx1->protocols, ctx2->protocols) != 0)
+               return 1;
 
        return ctx1->verify_client_cert == ctx2->verify_client_cert ? 0 : 1;
 }
@@ -603,6 +606,7 @@ ssl_server_context_get(const struct login_settings *set)
        lookup_ctx.key = set->ssl_key;
        lookup_ctx.ca = set->ssl_ca;
        lookup_ctx.cipher_list = set->ssl_cipher_list;
+       lookup_ctx.protocols = set->ssl_protocols;
        lookup_ctx.verify_client_cert = set->ssl_verify_client_cert;
 
        ctx = hash_table_lookup(ssl_servers, &lookup_ctx);
@@ -924,7 +928,9 @@ ssl_proxy_ctx_init(SSL_CTX *ssl_ctx, const struct login_settings *set)
        X509_STORE *store;
        STACK_OF(X509_NAME) *xnames = NULL;
 
-       SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+       /* enable all SSL workarounds */
+       SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+
        if (*set->ssl_ca != '\0') {
                /* set trusted CA certs */
                store = SSL_CTX_get_cert_store(ssl_ctx);
@@ -1091,6 +1097,57 @@ static void ssl_servername_callback(SSL *ssl, int *al ATTR_UNUSED,
 }
 #endif
 
+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->ctx, op);
+}
+
 static struct ssl_server_context *
 ssl_server_context_init(const struct login_settings *set)
 {
@@ -1106,6 +1163,7 @@ ssl_server_context_init(const struct login_settings *set)
        ctx->key = p_strdup(pool, set->ssl_key);
        ctx->ca = p_strdup(pool, set->ssl_ca);
        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->ctx = ssl_ctx = SSL_CTX_new(SSLv23_server_method());
@@ -1117,6 +1175,7 @@ ssl_server_context_init(const struct login_settings *set)
                i_fatal("Can't set cipher list to '%s': %s",
                        ctx->cipher_list, ssl_last_error());
        }
+       ssl_proxy_ctx_set_protocols(ctx, ctx->protocols);
 
        if (ssl_proxy_ctx_use_certificate_chain(ctx->ctx, ctx->cert) != 1) {
                i_fatal("Can't load ssl_cert: %s",