d0a457
From bc9ae5a810b8024e7ab1179f492c425793e0ddcf Mon Sep 17 00:00:00 2001
d0a457
From: Mark Reynolds <mreynolds@redhat.com>
d0a457
Date: Fri, 7 Jun 2019 09:21:31 -0400
d0a457
Subject: [PATCH] Issue 50426 - nsSSL3Ciphers is limited to 1024 characters
d0a457
d0a457
Bug Description:  There was a hardcoded buffer for processing TLS ciphers.
d0a457
                  Anything over 1024 characters was truncated and was not
d0a457
                  applied.
d0a457
d0a457
Fix Description:  Don't use a fixed size buffer and just use the entire
d0a457
                  string.  When printing errors about invalid format then
d0a457
                  we must use a fixed sized buffer, but we will truncate
d0a457
                  that log value as to not exceed the ssl logging function's
d0a457
                  buffer, and still output a useful message.
d0a457
d0a457
ASAN approved
d0a457
d0a457
https://pagure.io/389-ds-base/issue/50426
d0a457
d0a457
Reviewed by: firstyear, tbordaz, and spichugi (Thanks!!!)
d0a457
d0a457
(cherry picked from commit 22f2f9a1502e63bb169b7d599b5a3b35ddb31b8a)
d0a457
---
d0a457
 dirsrvtests/tests/suites/tls/cipher_test.py | 51 +++++++++++++++++++++
d0a457
 ldap/servers/slapd/ssl.c                    | 34 ++++++--------
d0a457
 2 files changed, 66 insertions(+), 19 deletions(-)
d0a457
 create mode 100644 dirsrvtests/tests/suites/tls/cipher_test.py
d0a457
d0a457
diff --git a/dirsrvtests/tests/suites/tls/cipher_test.py b/dirsrvtests/tests/suites/tls/cipher_test.py
d0a457
new file mode 100644
d0a457
index 000000000..058931046
d0a457
--- /dev/null
d0a457
+++ b/dirsrvtests/tests/suites/tls/cipher_test.py
d0a457
@@ -0,0 +1,51 @@
d0a457
+import pytest
d0a457
+import os
d0a457
+from lib389.config import Encryption
d0a457
+from lib389.topologies import topology_st as topo
d0a457
+
d0a457
+
d0a457
+def test_long_cipher_list(topo):
d0a457
+    """Test a long cipher list, and makre sure it is not truncated
d0a457
+
d0a457
+    :id: bc400f54-3966-49c8-b640-abbf4fb2377d
d0a457
+    :setup: Standalone Instance
d0a457
+    :steps:
d0a457
+        1. Set nsSSL3Ciphers to a very long list of ciphers
d0a457
+        2. Ciphers are applied correctly
d0a457
+    :expectedresults:
d0a457
+        1. Success
d0a457
+        2. Success
d0a457
+    """
d0a457
+    ENABLED_CIPHER = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384::AES-GCM::AEAD::256"
d0a457
+    DISABLED_CIPHER = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256::AES-GCM::AEAD::128"
d0a457
+    CIPHER_LIST = (
d0a457
+            "-all,-SSL_CK_RC4_128_WITH_MD5,-SSL_CK_RC4_128_EXPORT40_WITH_MD5,-SSL_CK_RC2_128_CBC_WITH_MD5,"
d0a457
+            "-SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5,-SSL_CK_DES_64_CBC_WITH_MD5,-SSL_CK_DES_192_EDE3_CBC_WITH_MD5,"
d0a457
+            "-TLS_RSA_WITH_RC4_128_MD5,-TLS_RSA_WITH_RC4_128_SHA,-TLS_RSA_WITH_3DES_EDE_CBC_SHA,"
d0a457
+            "-TLS_RSA_WITH_DES_CBC_SHA,-SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,-SSL_RSA_FIPS_WITH_DES_CBC_SHA,"
d0a457
+            "-TLS_RSA_EXPORT_WITH_RC4_40_MD5,-TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,-TLS_RSA_WITH_NULL_MD5,"
d0a457
+            "-TLS_RSA_WITH_NULL_SHA,-TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,-SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,"
d0a457
+            "-SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,-SSL_FORTEZZA_DMS_WITH_NULL_SHA,-TLS_DHE_DSS_WITH_DES_CBC_SHA,"
d0a457
+            "-TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,-TLS_DHE_RSA_WITH_DES_CBC_SHA,-TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,"
d0a457
+            "+TLS_RSA_WITH_AES_128_CBC_SHA,-TLS_DHE_DSS_WITH_AES_128_CBC_SHA,-TLS_DHE_RSA_WITH_AES_128_CBC_SHA,"
d0a457
+            "+TLS_RSA_WITH_AES_256_CBC_SHA,-TLS_DHE_DSS_WITH_AES_256_CBC_SHA,-TLS_DHE_RSA_WITH_AES_256_CBC_SHA,"
d0a457
+            "-TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,-TLS_DHE_DSS_WITH_RC4_128_SHA,-TLS_ECDHE_RSA_WITH_RC4_128_SHA,"
d0a457
+            "-TLS_RSA_WITH_NULL_SHA,-TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,-SSL_CK_DES_192_EDE3_CBC_WITH_MD5,"
d0a457
+            "-TLS_RSA_WITH_RC4_128_MD5,-TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,-TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,"
d0a457
+            "-TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,+TLS_AES_128_GCM_SHA256,+TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
d0a457
+        )
d0a457
+
d0a457
+    topo.standalone.enable_tls()
d0a457
+    enc = Encryption(topo.standalone)
d0a457
+    enc.set('nsSSL3Ciphers', CIPHER_LIST)
d0a457
+    topo.standalone.restart()
d0a457
+    enabled_ciphers = enc.get_attr_vals_utf8('nssslenabledciphers')
d0a457
+    assert ENABLED_CIPHER in enabled_ciphers
d0a457
+    assert DISABLED_CIPHER not in enabled_ciphers
d0a457
+
d0a457
+
d0a457
+if __name__ == '__main__':
d0a457
+    # Run isolated
d0a457
+    # -s for DEBUG mode
d0a457
+    CURRENT_FILE = os.path.realpath(__file__)
d0a457
+    pytest.main(["-s", CURRENT_FILE])
d0a457
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
d0a457
index b8eba2da4..ed054db44 100644
d0a457
--- a/ldap/servers/slapd/ssl.c
d0a457
+++ b/ldap/servers/slapd/ssl.c
d0a457
@@ -95,7 +95,6 @@ static char *configDN = "cn=encryption,cn=config";
d0a457
 #define CIPHER_SET_ALLOWWEAKDHPARAM 0x200    /* allowWeakDhParam is on */
d0a457
 #define CIPHER_SET_DISALLOWWEAKDHPARAM 0x400 /* allowWeakDhParam is off */
d0a457
 
d0a457
-
d0a457
 #define CIPHER_SET_ISDEFAULT(flag) \
d0a457
     (((flag)&CIPHER_SET_DEFAULT) ? PR_TRUE : PR_FALSE)
d0a457
 #define CIPHER_SET_ISALL(flag) \
d0a457
@@ -689,10 +688,12 @@ _conf_setciphers(char *setciphers, int flags)
d0a457
             active = 0;
d0a457
             break;
d0a457
         default:
d0a457
-            PR_snprintf(err, sizeof(err), "invalid ciphers <%s>: format is "
d0a457
-                                          "+cipher1,-cipher2...",
d0a457
-                        raw);
d0a457
-            return slapi_ch_strdup(err);
d0a457
+            if (strlen(raw) > MAGNUS_ERROR_LEN) {
d0a457
+                PR_snprintf(err, sizeof(err) - 3, "%s...", raw);
d0a457
+                return slapi_ch_smprintf("invalid ciphers <%s>: format is +cipher1,-cipher2...", err);
d0a457
+            } else {
d0a457
+                return slapi_ch_smprintf("invalid ciphers <%s>: format is +cipher1,-cipher2...", raw);
d0a457
+            }
d0a457
         }
d0a457
         if ((t = strchr(setciphers, ',')))
d0a457
             *t++ = '\0';
d0a457
@@ -1689,7 +1690,6 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
d0a457
     PRUint16 NSSVersionMax = enabledNSSVersions.max;
d0a457
     char mymin[VERSION_STR_LENGTH], mymax[VERSION_STR_LENGTH];
d0a457
     char newmax[VERSION_STR_LENGTH];
d0a457
-    char cipher_string[1024];
d0a457
     int allowweakcipher = CIPHER_SET_DEFAULTWEAKCIPHER;
d0a457
     int_fast16_t renegotiation = (int_fast16_t)SSL_RENEGOTIATE_REQUIRES_XTN;
d0a457
 
d0a457
@@ -1730,21 +1730,17 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
d0a457
                            "Ignoring it and set it to default.", val, configDN);
d0a457
         }
d0a457
     }
d0a457
-    slapi_ch_free((void **)&val;;
d0a457
+    slapi_ch_free_string(&val;;
d0a457
 
d0a457
     /* Set SSL cipher preferences */
d0a457
-    *cipher_string = 0;
d0a457
-    if (ciphers && (*ciphers) && PL_strcmp(ciphers, "blank"))
d0a457
-        PL_strncpyz(cipher_string, ciphers, sizeof(cipher_string));
d0a457
-    slapi_ch_free((void **)&ciphers);
d0a457
-
d0a457
-    if (NULL != (val = _conf_setciphers(cipher_string, allowweakcipher))) {
d0a457
+    if (NULL != (val = _conf_setciphers(ciphers, allowweakcipher))) {
d0a457
         errorCode = PR_GetError();
d0a457
         slapd_SSL_warn("Failed to set SSL cipher "
d0a457
                        "preference information: %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
d0a457
                        val, errorCode, slapd_pr_strerror(errorCode));
d0a457
-        slapi_ch_free((void **)&val;;
d0a457
+        slapi_ch_free_string(&val;;
d0a457
     }
d0a457
+    slapi_ch_free_string(&ciphers);
d0a457
     freeConfigEntry(&e);
d0a457
 
d0a457
     /* Import pr fd into SSL */
d0a457
@@ -1815,12 +1811,12 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
d0a457
             activation = slapi_entry_attr_get_charptr(e, "nssslactivation");
d0a457
             if ((!activation) || (!PL_strcasecmp(activation, "off"))) {
d0a457
                 /* this family was turned off, goto next */
d0a457
-                slapi_ch_free((void **)&activation);
d0a457
+                slapi_ch_free_string(&activation);
d0a457
                 freeConfigEntry(&e);
d0a457
                 continue;
d0a457
             }
d0a457
 
d0a457
-            slapi_ch_free((void **)&activation);
d0a457
+            slapi_ch_free_string(&activation);
d0a457
 
d0a457
             token = slapi_entry_attr_get_charptr(e, "nsssltoken");
d0a457
             personality = slapi_entry_attr_get_charptr(e, "nssslpersonalityssl");
d0a457
@@ -1837,8 +1833,8 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
d0a457
                                "family information. Missing nsssltoken or"
d0a457
                                "nssslpersonalityssl in %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
d0a457
                                *family, errorCode, slapd_pr_strerror(errorCode));
d0a457
-                slapi_ch_free((void **)&token);
d0a457
-                slapi_ch_free((void **)&personality);
d0a457
+                slapi_ch_free_string(&token);
d0a457
+                slapi_ch_free_string(&personality);
d0a457
                 freeConfigEntry(&e);
d0a457
                 continue;
d0a457
             }
d0a457
@@ -1865,7 +1861,7 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
d0a457
                                "private key for cert %s of family %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
d0a457
                                cert_name, *family,
d0a457
                                errorCode, slapd_pr_strerror(errorCode));
d0a457
-                slapi_ch_free((void **)&personality);
d0a457
+                slapi_ch_free_string(&personality);
d0a457
                 CERT_DestroyCertificate(cert);
d0a457
                 cert = NULL;
d0a457
                 freeConfigEntry(&e);
d0a457
-- 
d0a457
2.21.0
d0a457