|
|
232633 |
From 2307e77efb6a75091b9152f81a52c83b8282d61a Mon Sep 17 00:00:00 2001
|
|
|
232633 |
From: =?UTF-8?q?Mat=C3=BA=C5=A1=20Hon=C4=9Bk?= <mhonek@redhat.com>
|
|
|
232633 |
Date: Thu, 31 Jan 2019 10:44:55 +0100
|
|
|
232633 |
Subject: [PATCH 05/12] Ticket 50217 - Implement dsconf security section
|
|
|
232633 |
|
|
|
232633 |
Bug Description:
|
|
|
232633 |
dsconf lacks options to configure security options
|
|
|
232633 |
|
|
|
232633 |
Fix Description:
|
|
|
232633 |
Implementing options to configure security related attributes and handle ciphers
|
|
|
232633 |
configuration.
|
|
|
232633 |
|
|
|
232633 |
Fixes: https://pagure.io/389-ds-base/issue/50217
|
|
|
232633 |
|
|
|
232633 |
Author: Matus Honek <mhonek@redhat.com>
|
|
|
232633 |
|
|
|
232633 |
Review by: firstyear, mreynolds (Thanks!)
|
|
|
232633 |
---
|
|
|
232633 |
src/lib389/cli/dsconf | 2 +
|
|
|
232633 |
src/lib389/lib389/cli_conf/security.py | 244 +++++++++++++++++++++++++
|
|
|
232633 |
src/lib389/lib389/config.py | 97 +++++++++-
|
|
|
232633 |
src/lib389/lib389/nss_ssl.py | 7 +-
|
|
|
232633 |
4 files changed, 343 insertions(+), 7 deletions(-)
|
|
|
232633 |
create mode 100644 src/lib389/lib389/cli_conf/security.py
|
|
|
232633 |
|
|
|
232633 |
diff --git a/src/lib389/cli/dsconf b/src/lib389/cli/dsconf
|
|
|
232633 |
index f81516290..c0c0b4dfe 100755
|
|
|
232633 |
--- a/src/lib389/cli/dsconf
|
|
|
232633 |
+++ b/src/lib389/cli/dsconf
|
|
|
232633 |
@@ -32,6 +32,7 @@ from lib389.cli_conf import backup as cli_backup
|
|
|
232633 |
from lib389.cli_conf import replication as cli_replication
|
|
|
232633 |
from lib389.cli_conf import chaining as cli_chaining
|
|
|
232633 |
from lib389.cli_conf import conflicts as cli_repl_conflicts
|
|
|
232633 |
+from lib389.cli_conf import security as cli_security
|
|
|
232633 |
from lib389.cli_base import disconnect_instance, connect_instance
|
|
|
232633 |
from lib389.cli_base.dsrc import dsrc_to_ldap, dsrc_arg_concat
|
|
|
232633 |
from lib389.cli_base import setup_script_logger
|
|
|
232633 |
@@ -87,6 +88,7 @@ cli_plugin.create_parser(subparsers)
|
|
|
232633 |
cli_pwpolicy.create_parser(subparsers)
|
|
|
232633 |
cli_replication.create_parser(subparsers)
|
|
|
232633 |
cli_sasl.create_parser(subparsers)
|
|
|
232633 |
+cli_security.create_parser(subparsers)
|
|
|
232633 |
cli_schema.create_parser(subparsers)
|
|
|
232633 |
cli_repl_conflicts.create_parser(subparsers)
|
|
|
232633 |
|
|
|
232633 |
diff --git a/src/lib389/lib389/cli_conf/security.py b/src/lib389/lib389/cli_conf/security.py
|
|
|
232633 |
new file mode 100644
|
|
|
232633 |
index 000000000..6d8c1ae0f
|
|
|
232633 |
--- /dev/null
|
|
|
232633 |
+++ b/src/lib389/lib389/cli_conf/security.py
|
|
|
232633 |
@@ -0,0 +1,244 @@
|
|
|
232633 |
+# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
232633 |
+# Copyright (C) 2019 Red Hat, Inc.
|
|
|
232633 |
+# All rights reserved.
|
|
|
232633 |
+#
|
|
|
232633 |
+# License: GPL (version 3 or any later version).
|
|
|
232633 |
+# See LICENSE for details.
|
|
|
232633 |
+# --- END COPYRIGHT BLOCK ---
|
|
|
232633 |
+
|
|
|
232633 |
+from collections import OrderedDict, namedtuple
|
|
|
232633 |
+import json
|
|
|
232633 |
+
|
|
|
232633 |
+from lib389.config import Config, Encryption, RSA
|
|
|
232633 |
+from lib389.nss_ssl import NssSsl
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+Props = namedtuple('Props', ['cls', 'attr', 'help', 'values'])
|
|
|
232633 |
+
|
|
|
232633 |
+onoff = ('on', 'off')
|
|
|
232633 |
+protocol_versions = ('SSLv3', 'TLS1.0', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3', '')
|
|
|
232633 |
+SECURITY_ATTRS_MAP = OrderedDict([
|
|
|
232633 |
+ ('security', Props(Config, 'nsslapd-security',
|
|
|
232633 |
+ 'Enable or disable security',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+ ('listen-host', Props(Config, 'nsslapd-securelistenhost',
|
|
|
232633 |
+ 'Host/address to listen on for LDAPS',
|
|
|
232633 |
+ str)),
|
|
|
232633 |
+ ('secure-port', Props(Config, 'nsslapd-securePort',
|
|
|
232633 |
+ 'Port for LDAPS to listen on',
|
|
|
232633 |
+ range(1, 65536))),
|
|
|
232633 |
+ ('tls-client-auth', Props(Config, 'nsSSLClientAuth',
|
|
|
232633 |
+ 'Client authentication requirement',
|
|
|
232633 |
+ ('off', 'allowed', 'required'))),
|
|
|
232633 |
+ ('require-secure-authentication', Props(Config, 'nsslapd-require-secure-binds',
|
|
|
232633 |
+ 'Require binds over LDAPS, StartTLS, or SASL',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+ ('check-hostname', Props(Config, 'nsslapd-ssl-check-hostname',
|
|
|
232633 |
+ 'Check Subject of remote certificate against the hostname',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+ ('verify-cert-chain-on-startup', Props(Config, 'nsslapd-validate-cert',
|
|
|
232633 |
+ 'Validate server certificate during startup',
|
|
|
232633 |
+ ('warn', *onoff))),
|
|
|
232633 |
+ ('session-timeout', Props(Encryption, 'nsSSLSessionTimeout',
|
|
|
232633 |
+ 'Secure session timeout',
|
|
|
232633 |
+ int)),
|
|
|
232633 |
+ ('tls-protocol-min', Props(Encryption, 'sslVersionMin',
|
|
|
232633 |
+ 'Secure protocol minimal allowed version',
|
|
|
232633 |
+ protocol_versions)),
|
|
|
232633 |
+ ('tls-protocol-max', Props(Encryption, 'sslVersionMax',
|
|
|
232633 |
+ 'Secure protocol maximal allowed version',
|
|
|
232633 |
+ protocol_versions)),
|
|
|
232633 |
+ ('allow-insecure-ciphers', Props(Encryption, 'allowWeakCipher',
|
|
|
232633 |
+ 'Allow weak ciphers for legacy use',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+ ('allow-weak-dh-param', Props(Encryption, 'allowWeakDHParam',
|
|
|
232633 |
+ 'Allow short DH params for legacy use',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+])
|
|
|
232633 |
+
|
|
|
232633 |
+RSA_ATTRS_MAP = OrderedDict([
|
|
|
232633 |
+ ('tls-allow-rsa-certificates', Props(RSA, 'nsSSLActivation',
|
|
|
232633 |
+ 'Activate use of RSA certificates',
|
|
|
232633 |
+ onoff)),
|
|
|
232633 |
+ ('nss-cert-name', Props(RSA, 'nsSSLPersonalitySSL',
|
|
|
232633 |
+ 'Server certificate name in NSS DB',
|
|
|
232633 |
+ str)),
|
|
|
232633 |
+ ('nss-token', Props(RSA, 'nsSSLToken',
|
|
|
232633 |
+ 'Security token name (module of NSS DB)',
|
|
|
232633 |
+ str))
|
|
|
232633 |
+])
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_get(inst, basedn, logs, args, attrs_map):
|
|
|
232633 |
+ result = {}
|
|
|
232633 |
+ for attr, props in attrs_map.items():
|
|
|
232633 |
+ val = props.cls(inst).get_attr_val_utf8(props.attr)
|
|
|
232633 |
+ result[props.attr] = val
|
|
|
232633 |
+ if args.json:
|
|
|
232633 |
+ print(json.dumps({'type': 'list', 'items': result}))
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ print('\n'.join([f'{attr}: {value or ""}' for attr, value in result.items()]))
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_set(inst, basedn, logs, args, attrs_map):
|
|
|
232633 |
+ for attr, props in attrs_map.items():
|
|
|
232633 |
+ arg = getattr(args, attr.replace('-', '_'))
|
|
|
232633 |
+ if arg is None:
|
|
|
232633 |
+ continue
|
|
|
232633 |
+ dsobj = props.cls(inst)
|
|
|
232633 |
+ dsobj.replace(props.attr, arg)
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_get_parser(parent, attrs_map, help):
|
|
|
232633 |
+ p = parent.add_parser('get', help=help)
|
|
|
232633 |
+ p.set_defaults(func=lambda *args: _security_generic_get(*args, attrs_map))
|
|
|
232633 |
+ return p
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_set_parser(parent, attrs_map, help, description):
|
|
|
232633 |
+ p = parent.add_parser('set', help=help, description=description)
|
|
|
232633 |
+ p.set_defaults(func=lambda *args: _security_generic_set(*args, attrs_map))
|
|
|
232633 |
+ for opt, params in attrs_map.items():
|
|
|
232633 |
+ p.add_argument(f'--{opt}', help=f'{params[2]} ({params[1]})')
|
|
|
232633 |
+ return p
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_ciphers_change(mode, ciphers, inst, log):
|
|
|
232633 |
+ log = log.getChild('_security_ciphers_change')
|
|
|
232633 |
+ if ('default' in ciphers) or ('all' in ciphers):
|
|
|
232633 |
+ log.error(('Use ciphers\' names only. Keywords "default" and "all" are ignored. '
|
|
|
232633 |
+ 'Please, instead specify them manually using \'set\' command.'))
|
|
|
232633 |
+ return
|
|
|
232633 |
+ enc = Encryption(inst)
|
|
|
232633 |
+ if enc.change_ciphers(mode, ciphers) is False:
|
|
|
232633 |
+ log.error('Setting new ciphers failed.')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_toggle(inst, basedn, log, args, cls, attr, value, thing):
|
|
|
232633 |
+ cls(inst).set(attr, value)
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def _security_generic_toggle_parsers(parent, cls, attr, help_pattern):
|
|
|
232633 |
+ def add_parser(action, value):
|
|
|
232633 |
+ p = parent.add_parser(action.lower(), help=help_pattern.format(action))
|
|
|
232633 |
+ p.set_defaults(func=lambda *args: _security_generic_toggle(*args, cls, attr, value, action))
|
|
|
232633 |
+ return p
|
|
|
232633 |
+
|
|
|
232633 |
+ return list(map(add_parser, ('Enable', 'Disable'), ('on', 'off')))
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_enable(inst, basedn, log, args):
|
|
|
232633 |
+ dbpath = inst.get_cert_dir()
|
|
|
232633 |
+ tlsdb = NssSsl(dbpath=dbpath)
|
|
|
232633 |
+ if not tlsdb._db_exists(even_partial=True): # we want to be very careful
|
|
|
232633 |
+ log.info(f'Secure database does not exist. Creating a new one in {dbpath}.')
|
|
|
232633 |
+ tlsdb.reinit()
|
|
|
232633 |
+
|
|
|
232633 |
+ Config(inst).set('nsslapd-security', 'on')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_disable(inst, basedn, log, args):
|
|
|
232633 |
+ Config(inst).set('nsslapd-security', 'off')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_ciphers_enable(inst, basedn, log, args):
|
|
|
232633 |
+ _security_ciphers_change('+', args.cipher, inst, log)
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_ciphers_disable(inst, basedn, log, args):
|
|
|
232633 |
+ _security_ciphers_change('-', args.cipher, inst, log)
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_ciphers_set(inst, basedn, log, args):
|
|
|
232633 |
+ enc = Encryption(inst)
|
|
|
232633 |
+ enc.ciphers = args.cipher_string.split(',')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_ciphers_get(inst, basedn, log, args):
|
|
|
232633 |
+ enc = Encryption(inst)
|
|
|
232633 |
+ if args.json:
|
|
|
232633 |
+ print({'type': 'list', 'items': enc.ciphers})
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ val = ','.join(enc.ciphers)
|
|
|
232633 |
+ print(val if val != '' else '<undefined>')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def security_ciphers_list(inst, basedn, log, args):
|
|
|
232633 |
+ enc = Encryption(inst)
|
|
|
232633 |
+
|
|
|
232633 |
+ if args.enabled:
|
|
|
232633 |
+ lst = enc.enabled_ciphers
|
|
|
232633 |
+ elif args.supported:
|
|
|
232633 |
+ lst = enc.supported_ciphers
|
|
|
232633 |
+ elif args.disabled:
|
|
|
232633 |
+ lst = set(enc.supported_ciphers) - set(enc.enabled_ciphers)
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ lst = enc.ciphers
|
|
|
232633 |
+
|
|
|
232633 |
+ if args.json:
|
|
|
232633 |
+ print(json.dumps({'type': 'list', 'items': lst}))
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ if lst == []:
|
|
|
232633 |
+ log.getChild('security').warn('List of ciphers is empty')
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ print(*lst, sep='\n')
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
+def create_parser(subparsers):
|
|
|
232633 |
+ security = subparsers.add_parser('security', help='Query and manipulate security options')
|
|
|
232633 |
+ security_sub = security.add_subparsers(help='security')
|
|
|
232633 |
+ security_set = _security_generic_set_parser(security_sub, SECURITY_ATTRS_MAP, 'Set general security options',
|
|
|
232633 |
+ ('Use this command for setting security related options located in cn=config and cn=encryption,cn=config.'
|
|
|
232633 |
+ '\n\nTo enable/disable security you can use enable and disable commands instead.'))
|
|
|
232633 |
+ security_get = _security_generic_get_parser(security_sub, SECURITY_ATTRS_MAP, 'Get general security options')
|
|
|
232633 |
+ security_enable_p = security_sub.add_parser('enable', help='Enable security', description=(
|
|
|
232633 |
+ 'If missing, create security database, then turn on security functionality. Please note this is usually not'
|
|
|
232633 |
+ ' enought for TLS connections to work - proper setup of CA and server certificate is necessary.'))
|
|
|
232633 |
+ security_enable_p.set_defaults(func=security_enable)
|
|
|
232633 |
+ security_disable_p = security_sub.add_parser('disable', help='Disable security', description=(
|
|
|
232633 |
+ 'Turn off security functionality. The rest of the configuration will be left untouched.'))
|
|
|
232633 |
+ security_disable_p.set_defaults(func=security_disable)
|
|
|
232633 |
+
|
|
|
232633 |
+ rsa = security_sub.add_parser('rsa', help='Query and mainpulate RSA security options')
|
|
|
232633 |
+ rsa_sub = rsa.add_subparsers(help='rsa')
|
|
|
232633 |
+ rsa_set = _security_generic_set_parser(rsa_sub, RSA_ATTRS_MAP, 'Set RSA security options',
|
|
|
232633 |
+ ('Use this command for setting RSA (private key) related options located in cn=RSA,cn=encryption,cn=config.'
|
|
|
232633 |
+ '\n\nTo enable/disable RSA you can use enable and disable commands instead.'))
|
|
|
232633 |
+ rsa_get = _security_generic_get_parser(rsa_sub, RSA_ATTRS_MAP, 'Get RSA security options')
|
|
|
232633 |
+ rsa_toggles = _security_generic_toggle_parsers(rsa_sub, RSA, 'nsSSLActivation', '{} RSA')
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers = security_sub.add_parser('ciphers', help='Manage secure ciphers')
|
|
|
232633 |
+ ciphers_sub = ciphers.add_subparsers(help='ciphers')
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers_enable = ciphers_sub.add_parser('enable', help='Enable ciphers', description=(
|
|
|
232633 |
+ 'Use this command to enable specific ciphers.'))
|
|
|
232633 |
+ ciphers_enable.set_defaults(func=security_ciphers_enable)
|
|
|
232633 |
+ ciphers_enable.add_argument('cipher', nargs='+')
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers_disable = ciphers_sub.add_parser('disable', help='Disable ciphers', description=(
|
|
|
232633 |
+ 'Use this command to disable specific ciphers.'))
|
|
|
232633 |
+ ciphers_disable.set_defaults(func=security_ciphers_disable)
|
|
|
232633 |
+ ciphers_disable.add_argument('cipher', nargs='+')
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers_get = ciphers_sub.add_parser('get', help='Get ciphers attribute', description=(
|
|
|
232633 |
+ 'Use this command to get contents of nsSSL3Ciphers attribute.'))
|
|
|
232633 |
+ ciphers_get.set_defaults(func=security_ciphers_get)
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers_set = ciphers_sub.add_parser('set', help='Set ciphers attribute', description=(
|
|
|
232633 |
+ 'Use this command to directly set nsSSL3Ciphers attribute. It is a comma separated list '
|
|
|
232633 |
+ 'of cipher names (prefixed with + or -), optionaly including +all or -all. The attribute '
|
|
|
232633 |
+ 'may optionally be prefixed by keyword default. Please refer to documentation of '
|
|
|
232633 |
+ 'the attribute for a more detailed description.'))
|
|
|
232633 |
+ ciphers_set.set_defaults(func=security_ciphers_set)
|
|
|
232633 |
+ ciphers_set.add_argument('cipher_string', metavar='cipher-string')
|
|
|
232633 |
+
|
|
|
232633 |
+ ciphers_list = ciphers_sub.add_parser('list', help='List ciphers', description=(
|
|
|
232633 |
+ 'List secure ciphers. Without arguments, list ciphers as configured in nsSSL3Ciphers attribute.'))
|
|
|
232633 |
+ ciphers_list.set_defaults(func=security_ciphers_list)
|
|
|
232633 |
+ ciphers_list_group = ciphers_list.add_mutually_exclusive_group()
|
|
|
232633 |
+ ciphers_list_group.add_argument('--enabled', action='store_true',
|
|
|
232633 |
+ help='Only enabled ciphers')
|
|
|
232633 |
+ ciphers_list_group.add_argument('--supported', action='store_true',
|
|
|
232633 |
+ help='Only supported ciphers')
|
|
|
232633 |
+ ciphers_list_group.add_argument('--disabled', action='store_true',
|
|
|
232633 |
+ help='Only supported ciphers without enabled ciphers')
|
|
|
232633 |
diff --git a/src/lib389/lib389/config.py b/src/lib389/lib389/config.py
|
|
|
232633 |
index b462585df..c2a34fa07 100644
|
|
|
232633 |
--- a/src/lib389/lib389/config.py
|
|
|
232633 |
+++ b/src/lib389/lib389/config.py
|
|
|
232633 |
@@ -1,5 +1,5 @@
|
|
|
232633 |
# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
232633 |
-# Copyright (C) 2015 Red Hat, Inc.
|
|
|
232633 |
+# Copyright (C) 2019 Red Hat, Inc.
|
|
|
232633 |
# All rights reserved.
|
|
|
232633 |
#
|
|
|
232633 |
# License: GPL (version 3 or any later version).
|
|
|
232633 |
@@ -202,14 +202,16 @@ class Config(DSLdapObject):
|
|
|
232633 |
return DSCLE0002
|
|
|
232633 |
return None
|
|
|
232633 |
|
|
|
232633 |
+
|
|
|
232633 |
class Encryption(DSLdapObject):
|
|
|
232633 |
"""
|
|
|
232633 |
Manage "cn=encryption,cn=config" tree, including:
|
|
|
232633 |
- ssl ciphers
|
|
|
232633 |
- ssl / tls levels
|
|
|
232633 |
"""
|
|
|
232633 |
- def __init__(self, conn):
|
|
|
232633 |
+ def __init__(self, conn, dn=None):
|
|
|
232633 |
"""@param conn - a DirSrv instance """
|
|
|
232633 |
+ assert dn is None # compatibility with Config class
|
|
|
232633 |
super(Encryption, self).__init__(instance=conn)
|
|
|
232633 |
self._dn = 'cn=encryption,%s' % DN_CONFIG
|
|
|
232633 |
self._create_objectclasses = ['top', 'nsEncryptionConfig']
|
|
|
232633 |
@@ -225,11 +227,97 @@ class Encryption(DSLdapObject):
|
|
|
232633 |
super(Encryption, self).create(properties=properties)
|
|
|
232633 |
|
|
|
232633 |
def _lint_check_tls_version(self):
|
|
|
232633 |
- tls_min = self.get_attr_val('sslVersionMin');
|
|
|
232633 |
+ tls_min = self.get_attr_val('sslVersionMin')
|
|
|
232633 |
if tls_min < ensure_bytes('TLS1.1'):
|
|
|
232633 |
return DSELE0001
|
|
|
232633 |
return None
|
|
|
232633 |
|
|
|
232633 |
+ @property
|
|
|
232633 |
+ def ciphers(self):
|
|
|
232633 |
+ """List of requested ciphers.
|
|
|
232633 |
+
|
|
|
232633 |
+ Each is represented by a string, either of:
|
|
|
232633 |
+ - "+all" or "-all"
|
|
|
232633 |
+ - TLS cipher RFC name, prefixed with either "+" or "-"
|
|
|
232633 |
+
|
|
|
232633 |
+ Optionally, first element may be a string "default".
|
|
|
232633 |
+
|
|
|
232633 |
+ :returns: list of str
|
|
|
232633 |
+ """
|
|
|
232633 |
+ val = self.get_attr_val_utf8('nsSSL3Ciphers')
|
|
|
232633 |
+ return val.split(',') if val else []
|
|
|
232633 |
+
|
|
|
232633 |
+ @ciphers.setter
|
|
|
232633 |
+ def ciphers(self, ciphers):
|
|
|
232633 |
+ """List of requested ciphers.
|
|
|
232633 |
+
|
|
|
232633 |
+ :param ciphers: Ciphers to enable
|
|
|
232633 |
+ :type ciphers: list of str
|
|
|
232633 |
+ """
|
|
|
232633 |
+ self.set('nsSSL3Ciphers', ','.join(ciphers))
|
|
|
232633 |
+ self._log.info('Remeber to restart the server to apply the new cipher set.')
|
|
|
232633 |
+ self._log.info('Some ciphers may be disabled anyway due to allowWeakCipher attribute.')
|
|
|
232633 |
+
|
|
|
232633 |
+ def _get_listed_ciphers(self, attr):
|
|
|
232633 |
+ """Remove features of ciphers that come after first :: occurence."""
|
|
|
232633 |
+ return [c[:c.index('::')] for c in self.get_attr_vals_utf8(attr)]
|
|
|
232633 |
+
|
|
|
232633 |
+ @property
|
|
|
232633 |
+ def enabled_ciphers(self):
|
|
|
232633 |
+ """List currently enabled ciphers.
|
|
|
232633 |
+
|
|
|
232633 |
+ :returns: list of str
|
|
|
232633 |
+ """
|
|
|
232633 |
+ return self._get_listed_ciphers('nsSSLEnabledCiphers')
|
|
|
232633 |
+
|
|
|
232633 |
+ @property
|
|
|
232633 |
+ def supported_ciphers(self):
|
|
|
232633 |
+ """List currently supported ciphers.
|
|
|
232633 |
+
|
|
|
232633 |
+ :returns: list of str
|
|
|
232633 |
+ """
|
|
|
232633 |
+ return self._get_listed_ciphers('nsSSLSupportedCiphers')
|
|
|
232633 |
+
|
|
|
232633 |
+ def _check_ciphers_supported(self, ciphers):
|
|
|
232633 |
+ good = True
|
|
|
232633 |
+ for c in ciphers:
|
|
|
232633 |
+ if c not in self.supported_ciphers:
|
|
|
232633 |
+ self._log.warn(f'Cipher {c} is not supported.')
|
|
|
232633 |
+ good = False
|
|
|
232633 |
+ return good
|
|
|
232633 |
+
|
|
|
232633 |
+ def change_ciphers(self, mode, ciphers):
|
|
|
232633 |
+ """Enable or disable ciphers of the nsSSL3Ciphers attribute.
|
|
|
232633 |
+
|
|
|
232633 |
+ :param mode: '+'/'-' string to enable/disable the ciphers
|
|
|
232633 |
+ :type mode: str
|
|
|
232633 |
+ :param ciphers: List of ciphers to enable/disable
|
|
|
232633 |
+ :type ciphers: list of string
|
|
|
232633 |
+
|
|
|
232633 |
+ :returns: False if some cipher is not supported
|
|
|
232633 |
+ """
|
|
|
232633 |
+ if ('default' in ciphers) or 'all' in ciphers:
|
|
|
232633 |
+ raise NotImplementedError('Processing "default" and "all" is not implemented.')
|
|
|
232633 |
+ if not self._check_ciphers_supported(ciphers):
|
|
|
232633 |
+ return False
|
|
|
232633 |
+
|
|
|
232633 |
+ if mode == '+':
|
|
|
232633 |
+ to_change = [c for c in ciphers if c not in self.enabled_ciphers]
|
|
|
232633 |
+ elif mode == '-':
|
|
|
232633 |
+ to_change = [c for c in ciphers if c in self.enabled_ciphers]
|
|
|
232633 |
+ else:
|
|
|
232633 |
+ raise ValueError('Incorrect mode. Use - or + sign.')
|
|
|
232633 |
+ if len(to_change) != len(ciphers):
|
|
|
232633 |
+ self._log.info(
|
|
|
232633 |
+ ('Applying changes only for the following ciphers, the rest is up to date. '
|
|
|
232633 |
+ 'If this does not seem to be correct, please make sure the effective '
|
|
|
232633 |
+ 'set of enabled ciphers is up to date with configured ciphers '
|
|
|
232633 |
+ '- a server restart is needed for these to be applied.\n'
|
|
|
232633 |
+ f'... {to_change}'))
|
|
|
232633 |
+ cleaned = [c for c in self.ciphers if c[1:] not in to_change]
|
|
|
232633 |
+ self.ciphers = cleaned + list(map(lambda c: mode + c, to_change))
|
|
|
232633 |
+
|
|
|
232633 |
+
|
|
|
232633 |
class RSA(DSLdapObject):
|
|
|
232633 |
"""
|
|
|
232633 |
Manage the "cn=RSA,cn=encryption,cn=config" object
|
|
|
232633 |
@@ -237,8 +325,9 @@ class RSA(DSLdapObject):
|
|
|
232633 |
- Database path
|
|
|
232633 |
- ssl token name
|
|
|
232633 |
"""
|
|
|
232633 |
- def __init__(self, conn):
|
|
|
232633 |
+ def __init__(self, conn, dn=None):
|
|
|
232633 |
"""@param conn - a DirSrv instance """
|
|
|
232633 |
+ assert dn is None # compatibility with Config class
|
|
|
232633 |
super(RSA, self).__init__(instance=conn)
|
|
|
232633 |
self._dn = 'cn=RSA,cn=encryption,%s' % DN_CONFIG
|
|
|
232633 |
self._create_objectclasses = ['top', 'nsEncryptionModule']
|
|
|
232633 |
diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py
|
|
|
232633 |
index 7a8f2a5bd..a54095cd4 100644
|
|
|
232633 |
--- a/src/lib389/lib389/nss_ssl.py
|
|
|
232633 |
+++ b/src/lib389/lib389/nss_ssl.py
|
|
|
232633 |
@@ -162,11 +162,12 @@ only.
|
|
|
232633 |
self.log.debug("nss output: %s", result)
|
|
|
232633 |
return True
|
|
|
232633 |
|
|
|
232633 |
- def _db_exists(self):
|
|
|
232633 |
+ def _db_exists(self, even_partial=False):
|
|
|
232633 |
"""Check that a nss db exists at the certpath"""
|
|
|
232633 |
|
|
|
232633 |
- if all(map(os.path.exists, self.db_files["dbm_backend"])) or \
|
|
|
232633 |
- all(map(os.path.exists, self.db_files["sql_backend"])):
|
|
|
232633 |
+ fn = any if even_partial else all
|
|
|
232633 |
+ if fn(map(os.path.exists, self.db_files["dbm_backend"])) or \
|
|
|
232633 |
+ fn(map(os.path.exists, self.db_files["sql_backend"])):
|
|
|
232633 |
return True
|
|
|
232633 |
return False
|
|
|
232633 |
|
|
|
232633 |
--
|
|
|
232633 |
2.21.0
|
|
|
232633 |
|