From 4b26d2d7244eeaa481871c337e57cd393fd76dfe Mon Sep 17 00:00:00 2001
From: "Jeroen van Meeuwen (Kolab Systems)" <vanmeeuwen@kolabsys.com>
Date: Thu, 16 Oct 2014 11:12:20 +0200
Subject: Enhance SSL/TLS configuration options

New settings:

    tls_compression: 0

        Enable TLS compression. Disabled by default.

    tls_eccurve: prime256v1

        Select the elliptic curve used for ECDHE.

    tls_prefer_server_ciphers: 0

        Prefer the cipher order configured on the server-side.

    tls_versions: ssl2 ssl3 tls1_0 tls1_1 tls1_2

        Disable SSL/TLS protocols not in this list.

Bugzilla #3822, #3830, #3843, #3861.
---
 imap/tls.c      | 75 ++++++++++++++++++++++++++++++++++++++++++++-------------
 imtest/imtest.c |  2 +-
 lib/imapoptions | 16 ++++++++++++
 3 files changed, 75 insertions(+), 18 deletions(-)

Index: cyrus-imapd-2.3.11/imap/tls.c
===================================================================
--- cyrus-imapd-2.3.11.orig/imap/tls.c
+++ cyrus-imapd-2.3.11/imap/tls.c
@@ -626,6 +626,7 @@ int     tls_init_serverengine(const char
     const char   *s_key_file;
     const char   *ec;
     int    requirecert;
+    int    server_cipher_order;
     int    timeout;
 
     if (tls_serverengine)
@@ -641,13 +642,6 @@ int     tls_init_serverengine(const char
 	return -1;
     }
 
-#if 0
-    if (tlsonly) {
-	s_ctx = SSL_CTX_new(TLSv1_server_method());
-    } else {
-	s_ctx = SSL_CTX_new(SSLv23_server_method());
-    }
-#endif
     /* even if we want TLS only, we use SSLv23 server method so we can
        deal with a client sending an SSLv2 greeting message */
 
@@ -656,12 +650,40 @@ int     tls_init_serverengine(const char
 	return (-1);
     };
 
-    off |= SSL_OP_ALL;		/* Work around all known bugs */
-    if (tlsonly) {
-	off |= SSL_OP_NO_SSLv2;
-	off |= SSL_OP_NO_SSLv3;
+
+    const char *tls_versions = config_getstring(IMAPOPT_TLS_VERSIONS);
+
+    if (strstr(tls_versions, "ssl2") == NULL || tlsonly) {
+    	off |= SSL_OP_NO_SSLv2;
+    }
+
+    if (strstr(tls_versions, "ssl3") == NULL || tlsonly) {
+     	off |= SSL_OP_NO_SSLv3;
     }
 
+    if (strstr(tls_versions, "tls1_2") == NULL) {
+#if (OPENSSL_VERSION_NUMBER >= 0x1000105fL)
+    	off |= SSL_OP_NO_TLSv1_2;
+#else
+        syslog(LOG_ERR, "ERROR: TLSv1.2 configured, OpenSSL < 1.0.1e insufficient");
+#endif
+    }
+
+    if (strstr(tls_versions, "tls1_1") == NULL) {
+#if (OPENSSL_VERSION_NUMBER >= 0x1000000fL)
+        off |= SSL_OP_NO_TLSv1_1;
+#else
+        syslog(LOG_ERR, "ERROR: TLSv1.1 configured, OpenSSL < 1.0.0 insufficient");
+#endif
+    }
+    if (strstr(tls_versions, "tls1_0") == NULL) {
+        off |= SSL_OP_NO_TLSv1;
+    }
+
+    server_cipher_order = config_getswitch(IMAPOPT_TLS_PREFER_SERVER_CIPHERS);
+    if (server_cipher_order)
+        off |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+
     SSL_CTX_set_options(s_ctx, off);
 
 #ifdef SSL_OP_NO_COMPRESSION
@@ -724,10 +746,15 @@ int     tls_init_serverengine(const char
     CAfile = config_getstring(IMAPOPT_TLS_CA_FILE);
     CApath = config_getstring(IMAPOPT_TLS_CA_PATH);
 
-    if ((!SSL_CTX_load_verify_locations(s_ctx, CAfile, CApath)) ||
-	(!SSL_CTX_set_default_verify_paths(s_ctx))) {
-	/* just a warning since this is only necessary for client auth */
-	syslog(LOG_NOTICE,"TLS server engine: cannot load CA data");	
+    if (CAfile || CApath) {
+	if ((!SSL_CTX_load_verify_locations(s_ctx, CAfile, CApath)) ||
+	    (!SSL_CTX_set_default_verify_paths(s_ctx))) {
+	    /* just a warning since this is only necessary for client auth */
+	    syslog(LOG_NOTICE,"TLS server engine: cannot load CA data. Disabling client certs.");
+	    askcert = 0;
+	}
+    } else {
+	askcert = 0;
     }
 
     s_cert_file = config_getstring(IMAPOPT_TLS_CERT_FILE);
@@ -774,7 +801,7 @@ int     tls_init_serverengine(const char
       if (CAfile == NULL) {
 	  syslog(LOG_ERR, 
 		 "TLS server engine: No CA file specified. "
-		 "Client side certs may not work");
+		 "Client side certs will not work.");
       } else {
 	  SSL_CTX_set_client_CA_list(s_ctx, SSL_load_client_CA_file(CAfile));
       }
@@ -1215,7 +1242,7 @@ int tls_init_clientengine(int verifydept
 	return -1;
     }
     
-    c_ctx = SSL_CTX_new(TLSv1_client_method());
+    c_ctx = SSL_CTX_new(SSLv23_client_method());
     if (c_ctx == NULL) {
 	return (-1);
     };
@@ -1230,7 +1257,7 @@ int tls_init_clientengine(int verifydept
     if ((!SSL_CTX_load_verify_locations(c_ctx, CAfile, CApath)) ||
 	(!SSL_CTX_set_default_verify_paths(c_ctx))) {
 	/* just a warning since this is only necessary for client auth */
-	syslog(LOG_NOTICE,"TLS client engine: cannot load CA data");	
+	syslog(LOG_NOTICE,"TLS client engine: cannot load CA data");
     }
 
     if (strlen(var_tls_cert_file) == 0)
Index: cyrus-imapd-2.3.11/imtest/imtest.c
===================================================================
--- cyrus-imapd-2.3.11.orig/imtest/imtest.c
+++ cyrus-imapd-2.3.11/imtest/imtest.c
@@ -497,7 +497,7 @@ static int tls_init_clientengine(int ver
 	return IMTEST_FAIL;
     }
     
-    tls_ctx = SSL_CTX_new(TLSv1_client_method());
+    tls_ctx = SSL_CTX_new(SSLv23_client_method());
     if (tls_ctx == NULL) {
 	return IMTEST_FAIL;
     };
Index: cyrus-imapd-2.3.11/lib/imapoptions
===================================================================
--- cyrus-imapd-2.3.11.orig/lib/imapoptions
+++ cyrus-imapd-2.3.11/lib/imapoptions
@@ -1052,10 +1052,20 @@ are listed with ``<none>''.
 /* The list of SSL/TLS ciphers to allow.  The format of the string is
    described in ciphers(1). */
 
+{ "tls_compression", 0, SWITCH }
+/* deactivate TLS compression by default */
+
+{ "tls_eccurve", "prime256v1", STRING }
+/* The elliptic curve used for ECDHE. Default is NIST Suite B prime256.
+   See 'openssl ecparam -list_curves' for possible values. */
+
 { "tls_key_file", NULL, STRING }
 /* File containing the private key belonging to the server
    certificate.  A value of "disabled" will disable SSL/TLS. */
 
+{ "tls_prefer_server_ciphers", 0, SWITCH }
+/* Prefer the ciphers on the server side instead of client side */
+
 { "tls_require_cert", 0, SWITCH }
 /* Require a client certificate for ALL services (imap, pop3, lmtp, sieve). */
 
@@ -1068,6 +1078,12 @@ are listed with ``<none>''.
 /* The default elliptical curve parameter.
    For list of curves see: openssl ecparam -list_curves */
 
+{ "tls_versions", "ssl2 ssl3 tls1_0 tls1_1 tls1_2", STRING }
+/* A list of SSL/TLS versions to not disable. Cyrus IMAP SSL/TLS starts
+   with all protocols, and substracts protocols not in this list. Newer
+   versions of SSL/TLS will need to be added here to allow them to get
+   disabled. */
+
 { "umask", "077", STRING }
 /* The umask value used by various Cyrus IMAP programs. */
 
