On 2016-01-29 15:05, Martin Basti wrote:
> 
> 
> On 29.01.2016 14:42, Christian Heimes wrote:
>> On 2016-01-28 09:47, Martin Basti wrote:
>>>
>>> On 22.01.2016 12:32, Martin Kosek wrote:
>>>> On 01/21/2016 04:21 PM, Christian Heimes wrote:
>>>>> The list of supported TLS cipher suites in /etc/httpd/conf.d/nss.conf
>>>>> has been modernized. Insecure or less secure algorithms such as RC4,
>>>>> DES and 3DES are removed. Perfect forward secrecy suites with
>>>>> ephemeral
>>>>> ECDH key exchange have been added. IE 8 on Windows XP is no longer
>>>>> supported.
>>>>>
>>>>> The list of enabled cipher suites has been generated with the script
>>>>> contrib/nssciphersuite/nssciphersuite.py.
>>>>>
>>>>> The supported suites are currently:
>>>>>
>>>>> TLS_RSA_WITH_AES_128_CBC_SHA256
>>>>> TLS_RSA_WITH_AES_256_CBC_SHA256
>>>>> TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
>>>>> TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
>>>>> TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
>>>>> TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
>>>>> TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
>>>>> TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
>>>>> TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
>>>>> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
>>>>> TLS_RSA_WITH_AES_128_GCM_SHA256
>>>>> TLS_RSA_WITH_AES_128_CBC_SHA
>>>>> TLS_RSA_WITH_AES_256_GCM_SHA384
>>>>> TLS_RSA_WITH_AES_256_CBC_SHA
>>>>>
>>>>> https://fedorahosted.org/freeipa/ticket/5589
>>>> Thanks for the patch! I updated the ticket to make sure this change is
>>>> release notes.
>>>>
>>> Hello,
>>>
>>> I'm not sure if I'm the right person to do review on this, but I will
>>> try :-)
>>>
>>> 1)
>>> Your patch adds whitespace error
>>>
>>> Applying: Modernize mod_nss's cipher suites
>>> /home/mbasti/work/freeipa-devel/.git/rebase-apply/patch:52: new blank
>>> line at EOF.
>>> +
>>> warning: 1 line adds whitespace errors.
>>>
>>>
>>> 2)
>>> +import urllib.request  # pylint: disable=E0611
>>>
>>> Please specify pylint disabled check by name
>>>
>>> 3)
>>> +def update_mod_nss_cipher_suite(http):
>>>
>>> in this upgrade, is there any possibility that ciphers might be upgraded
>>> again in future? (IMO yes).
>>>
>>> I think, it can be better to store revision of change instead of boolean
>>>
>>> LAST_REVISION =  1
>>>
>>> if revision >= LAST_REVISION:
>>>      return
>>>
>>> sysupgrade.set_upgrade_state('nss.conf', 'cipher_suite_revision',
>>> LAST_REVISION)
>> Thanks for the review. I have addressed the problems. Instead of a
>> revision number I'm using a date string. The sysupgrade module only
>> stores str and bool. With a date-based revision it's easy to see when
>> the cipher suite was checked last time.
>>
>> Christian
>>
> 
> Thanks
> 
> 1) Pylint :-)
> +    with urllib.request.urlopen(SOURCE) as r:  # pylint: disable=E1101

Thanks! It was easier to change the import to get rid of the second
pylint stanza.

> 2)
> +    if revision == httpinstance.NSS_CIPHER_REVISION:
> 
> may happen a case where just comparation with '==' can cause a issues
> (docker world)? Should not be there rather '>='?

Makes sense, I've changed the comparison operator to >=. This may still
override user settings, though.

> 
> 3)
> +        root_logger.info("Cipher suite already updated")
> 
> Sorry that I did not noticed earlier, this should be just debug level,
> IMO this message is not so important, it will cause only mess on output
> (we already have plenty of unneeded info messages in upgrade, they will
> be fixed once)

Fine with me :)

Christian
From c8adc1472e06242d02119b39f3ac94413cab4229 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Thu, 21 Jan 2016 16:09:10 +0100
Subject: [PATCH] Modernize mod_nss's cipher suites

The list of supported TLS cipher suites in /etc/httpd/conf.d/nss.conf
has been modernized. Insecure or less secure algorithms such as RC4,
DES and 3DES are removed. Perfect forward secrecy suites with ephemeral
ECDH key exchange have been added. IE 8 on Windows XP is no longer
supported.

The list of enabled cipher suites has been generated with the script
contrib/nssciphersuite/nssciphersuite.py.

TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA

https://fedorahosted.org/freeipa/ticket/5589

Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 contrib/nssciphersuite/README.txt        |  37 ++++++++
 contrib/nssciphersuite/nssciphersuite.py | 148 +++++++++++++++++++++++++++++++
 ipaserver/install/httpinstance.py        |  19 ++++
 ipaserver/install/server/upgrade.py      |  18 ++++
 4 files changed, 222 insertions(+)
 create mode 100644 contrib/nssciphersuite/README.txt
 create mode 100755 contrib/nssciphersuite/nssciphersuite.py

diff --git a/contrib/nssciphersuite/README.txt b/contrib/nssciphersuite/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..725f2588b7840dc9cc22d9c03d6cb205f5c9fc09
--- /dev/null
+++ b/contrib/nssciphersuite/README.txt
@@ -0,0 +1,37 @@
+Cipher suite for mod_nss
+------------------------
+
+The nssciphersuite.py script parses mod_nss' nss_engine_cipher.c file and
+creates a list of secure cipher suites for TLS. The script filters out
+insecure, obsolete and slow ciphers according to some rules.
+
+As of January 2016 and mod_nss 1.0.12 the cipher suite list contains 14
+cipher suites for TLS 1.0, 1.1 and 1.2 for RSA and ECDSA certificates. The
+cipher suite list also supports Perfect Forward Secrecy with ephemeral ECDH
+key exchange. https://www.ssllabs.com/ gives a 'A' grade.
+
+Note:
+No suite is compatible with IE 8 and earlier on Windows XP. If you need IE 8
+support, append "+rsa_3des_sha" to enable TLS_RSA_WITH_3DES_EDE_CBC_SHA.
+
+# disabled cipher attributes: SSL_3DES, SSL_CAMELLIA, SSL_CAMELLIA128, SSL_CAMELLIA256, SSL_DES, SSL_DSS, SSL_MD5, SSL_RC2, SSL_RC4, SSL_aDSS, SSL_aNULL, SSL_eNULL, SSL_kECDHe, SSL_kECDHr, kECDH
+# weak strength: SSL_EXPORT40, SSL_EXPORT56, SSL_LOW, SSL_STRONG_NONE
+# enabled cipher suites:
+#   TLS_RSA_WITH_AES_128_CBC_SHA256
+#   TLS_RSA_WITH_AES_256_CBC_SHA256
+#   TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+#   TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+#   TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+#   TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+#   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+#   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+#   TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+#   TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+#   TLS_RSA_WITH_AES_128_GCM_SHA256
+#   TLS_RSA_WITH_AES_128_CBC_SHA
+#   TLS_RSA_WITH_AES_256_GCM_SHA384
+#   TLS_RSA_WITH_AES_256_CBC_SHA
+#
+
+NSSCipherSuite +aes_128_sha_256,+aes_256_sha_256,+ecdhe_ecdsa_aes_128_gcm_sha_256,+ecdhe_ecdsa_aes_128_sha,+ecdhe_ecdsa_aes_256_gcm_sha_384,+ecdhe_ecdsa_aes_256_sha,+ecdhe_rsa_aes_128_gcm_sha_256,+ecdhe_rsa_aes_128_sha,+ecdhe_rsa_aes_256_gcm_sha_384,+ecdhe_rsa_aes_256_sha,+rsa_aes_128_gcm_sha_256,+rsa_aes_128_sha,+rsa_aes_256_gcm_sha_384,+rsa_aes_256_sha
+
diff --git a/contrib/nssciphersuite/nssciphersuite.py b/contrib/nssciphersuite/nssciphersuite.py
new file mode 100755
index 0000000000000000000000000000000000000000..1b98fe37051afd8ebd3a1c12124105d30d4cbbe2
--- /dev/null
+++ b/contrib/nssciphersuite/nssciphersuite.py
@@ -0,0 +1,148 @@
+#!/usr/bin/python3
+#
+# Authors:
+#     Christian Heimes <chei...@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+"""Generate safe NSSCipherSuite stanza for mod_nss
+"""
+from __future__ import print_function
+
+import operator
+import re
+from urllib.request import urlopen  # pylint: disable=no-name-in-module
+
+SOURCE = "https://git.fedorahosted.org/cgit/mod_nss.git/plain/nss_engine_cipher.c";
+
+CIPHER_RE = re.compile(
+    r'\s*\{'
+    r'\"(?P<name>\w+)\",\s*'
+    r'(?P<num>(TLS|SSL)_\w+),\s*'
+    r'\"(?P<openssl_name>[\w-]+)\",\s*'
+    r'(?P<attr>[\w|]+),\s*'
+    r'(?P<version>\w+),\s*'
+    r'(?P<strength>\w+),\s*'
+    r'(?P<bits>\d+),\s*'
+    r'(?P<alg_bits>\d+)'
+)
+
+DISABLED_CIPHERS = {
+    # ciphers without encryption or authentication
+    'SSL_eNULL', 'SSL_aNULL',
+    # MD5 is broken
+    # SHA-1 is still required as PRF algorithm for TLSv1.0
+    'SSL_MD5',
+    # RC2 and RC4 stream ciphers are broken.
+    'SSL_RC2', 'SSL_RC4',
+    # DES is broken and Triple DES is too weak.
+    'SSL_DES', 'SSL_3DES',
+    # DSA is problematic.
+    'SSL_DSS', 'SSL_aDSS',
+    # prefer AES over Camellia.
+    'SSL_CAMELLIA128', 'SSL_CAMELLIA256', 'SSL_CAMELLIA',
+    # non-ephemeral EC Diffie-Hellmann with fixed parameters are not
+    # used by common browser and are therefore irrelevant for HTTPS.
+    'kECDH', 'SSL_kECDHr', 'SSL_kECDHe'
+}
+
+WEAK_STRENGTH = {
+    'SSL_STRONG_NONE',
+    'SSL_EXPORT40',
+    'SSL_EXPORT56',
+    'SSL_LOW'
+}
+
+
+def parse_nss_engine_cipher(lines, encoding='utf-8'):
+    """Parse nss_engine_cipher.c and get list of ciphers
+
+    :param lines: iterable or list of lines
+    :param encoding: default encoding
+    :return: list of cipher dicts
+    """
+    ciphers = []
+    start = False
+    for line in lines:
+        if not isinstance(line, str):
+            line = line.decode(encoding)
+
+        if line.startswith('cipher_properties'):
+            start = True
+        elif not start:
+            continue
+        elif line.startswith('};'):
+            break
+
+        mo = CIPHER_RE.match(line)
+        if not mo:
+            continue
+
+        match = mo.groupdict()
+        match['attr'] = set(match['attr'].split('|'))
+        match['bits'] = int(match['bits'])
+        match['alg_bits'] = int(match['alg_bits'])
+
+        # some cipher elemets aren't flagged
+        for algo in ['SHA256', 'SHA384']:
+            if match['num'].endswith(algo):
+                match['attr'].add('SSL_{}'.format(algo))
+
+        # cipher block chaining isn't tracked
+        if '_CBC' in match['num']:
+            match['attr'].add('SSL_CBC')
+
+        if match['attr'].intersection(DISABLED_CIPHERS):
+            match['enabled'] = False
+        elif match['strength'] in WEAK_STRENGTH:
+            match['enabled'] = False
+        else:
+            match['enabled'] = True
+
+        # EECDH + AES-CBC and large hash functions is slow and not more secure
+        if (match['attr'].issuperset({'SSL_CBC', 'SSL_kEECDH'}) and
+                match['attr'].intersection({'SSL_SHA256', 'SSL_SHA384'})):
+            match['enabled'] = False
+
+        ciphers.append(match)
+
+    ciphers.sort(key=operator.itemgetter('name'))
+    return ciphers
+
+
+def main():
+    with urlopen(SOURCE) as r:
+        ciphers = parse_nss_engine_cipher(r)
+    # with open('nss_engine_cipher.c') as f:
+    #     ciphers = parse_nss_engine_cipher(f)
+
+    print("# disabled cipher attributes: {}".format(
+        ', '.join(sorted(DISABLED_CIPHERS))))
+    print("# weak strength: {}".format(', '.join(sorted(WEAK_STRENGTH))))
+    print("# enabled cipher suites:")
+    suite = []
+    for cipher in ciphers:
+        if cipher['enabled']:
+            print("#   {:36}".format(cipher['num']))
+            suite.append('+{}'.format(cipher['name']))
+    print()
+    print("NSSCipherSuite {}".format(','.join(suite)))
+
+
+if __name__ == '__main__':
+    main()
+
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 3b46dce82cae017328c9555c543e78b64e642c89..44e0a7fe087ee2420e827c878b63010c7650989a 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -57,6 +57,19 @@ SELINUX_BOOLEAN_SETTINGS = dict(
 KDCPROXY_USER = 'kdcproxy'
 HTTPD_USER = constants.HTTPD_USER
 
+# See contrib/nsscipersuite/nssciphersuite.py
+NSS_CIPHER_SUITE = [
+    '+aes_128_sha_256', '+aes_256_sha_256',
+    '+ecdhe_ecdsa_aes_128_gcm_sha_256', '+ecdhe_ecdsa_aes_128_sha',
+    '+ecdhe_ecdsa_aes_256_gcm_sha_384', '+ecdhe_ecdsa_aes_256_sha',
+    '+ecdhe_rsa_aes_128_gcm_sha_256', '+ecdhe_rsa_aes_128_sha',
+    '+ecdhe_rsa_aes_256_gcm_sha_384', '+ecdhe_rsa_aes_256_sha',
+    '+rsa_aes_128_gcm_sha_256', '+rsa_aes_128_sha',
+    '+rsa_aes_256_gcm_sha_384', '+rsa_aes_256_sha'
+]
+NSS_CIPHER_REVISION = '20160129'
+
+
 def httpd_443_configured():
     """
     We now allow mod_ssl to be installed so don't automatically disable it.
@@ -146,6 +159,8 @@ class HTTPInstance(service.Service):
 
 
         self.step("setting mod_nss port to 443", self.__set_mod_nss_port)
+        self.step("setting mod_nss cipher suite",
+                  self.set_mod_nss_cipher_suite)
         self.step("setting mod_nss protocol list to TLSv1.0 - TLSv1.2",
                   self.set_mod_nss_protocol)
         self.step("setting mod_nss password file", self.__set_mod_nss_passwordfile)
@@ -255,6 +270,10 @@ class HTTPInstance(service.Service):
         installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRenegotiation', 'on', False)
         installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRequireSafeNegotiation', 'on', False)
 
+    def set_mod_nss_cipher_suite(self):
+        ciphers = ','.join(NSS_CIPHER_SUITE)
+        installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSCipherSuite', ciphers, False)
+
     def __set_mod_nss_passwordfile(self):
         installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSPassPhraseDialog', 'file:' + paths.HTTPD_PASSWORD_CONF)
 
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 48f8579a4bf49c9e225733facb06fcc001dbdb32..584a5fc13a22f8de7eef96352afc72d53d738542 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1343,6 +1343,23 @@ def update_mod_nss_protocol(http):
 
     sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True)
 
+
+def update_mod_nss_cipher_suite(http):
+    root_logger.info('[Updating mod_nss cipher suite]')
+
+    revision = sysupgrade.get_upgrade_state('nss.conf', 'cipher_suite_updated')
+    if revision >= httpinstance.NSS_CIPHER_REVISION:
+        root_logger.debug("Cipher suite already updated")
+        return
+
+    http.set_mod_nss_cipher_suite()
+
+    sysupgrade.set_upgrade_state(
+        'nss.conf',
+        'cipher_suite_updated',
+        httpinstance.NSS_CIPHER_REVISION)
+
+
 def ds_enable_sidgen_extdom_plugins(ds):
     """For AD trust agents, make sure we enable sidgen and extdom plugins
     """
@@ -1526,6 +1543,7 @@ def upgrade_configuration():
 
     http.stop()
     update_mod_nss_protocol(http)
+    update_mod_nss_cipher_suite(http)
     fix_trust_flags()
     export_kra_agent_pem()
     http.start()
-- 
2.5.0

Attachment: signature.asc
Description: OpenPGP digital signature

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to