URL: https://github.com/freeipa/freeipa/pull/367
Author: stlaz
 Title: #367: Remove nsslib from IPA
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/367/head:pr367
git checkout pr367
From 72343881600556e394923489643029781474bd93 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 20 Dec 2016 10:05:36 +0100
Subject: [PATCH 1/7] Remove NSSConnection from the Python RPC module

NSSConnection was causing a lot of trouble in the past and there is
a lot of logic around it just to make it not fail. What's more,
when using NSS to create an SSL connection in FIPS mode, NSS
always requires database password which makes the `ipa` command
totally unusable.

NSSConnection is therefore replaced with Python's
httplib.HTTPSConnection which is OpenSSL based.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipalib/config.py    |  3 ++
 ipalib/constants.py |  1 +
 ipalib/rpc.py       | 69 ++++++++------------------------------
 ipalib/util.py      | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 113 insertions(+), 55 deletions(-)

diff --git a/ipalib/config.py b/ipalib/config.py
index 20591db..8ecada6 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -493,6 +493,9 @@ def _bootstrap(self, **overrides):
         if 'nss_dir' not in self:
             self.nss_dir = self._join('confdir', 'nssdb')
 
+        if 'ca_certfile' not in self:
+            self.ca_certfile = self._join('confdir', 'ca.crt')
+
         # Set plugins_on_demand:
         if 'plugins_on_demand' not in self:
             self.plugins_on_demand = (self.context == 'cli')
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 81643da..4f40545 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -226,6 +226,7 @@
     ('conf_default', object),  # File containing context independent config
     ('plugins_on_demand', object),  # Whether to finalize plugins on-demand (bool)
     ('nss_dir', object),  # Path to nssdb, default {confdir}/nssdb
+    ('ca_certfile', object),  # Path to CA cert file
 
     # Set in Env._finalize_core():
     ('in_server', object),  # Whether or not running in-server (bool)
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 921f5cb..66cd1c3 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -44,7 +44,7 @@
 import gssapi
 from dns import resolver, rdatatype
 from dns.exception import DNSException
-from nss.error import NSPRError
+from ssl import SSLError
 import six
 from six.moves import urllib
 
@@ -60,8 +60,7 @@
 from ipapython.cookie import Cookie
 from ipapython.dnsutil import DNSName
 from ipalib.text import _
-import ipapython.nsslib
-from ipapython.nsslib import NSSConnection
+from ipalib.util import IPAHTTPSConnection
 from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT_EXPIRED, \
                              KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, \
                              KRB5_REALM_CANT_RESOLVE, KRB5_CC_NOTFOUND, get_principal
@@ -470,48 +469,21 @@ def get_host_info(self, host):
 
         return (host, extra_headers, x509)
 
+
 class SSLTransport(LanguageAwareTransport):
     """Handles an HTTPS transaction to an XML-RPC server."""
-
-    def get_connection_dbdir(self):
-        """
-        If there is a connections open it may have already initialized
-        NSS database. Return the database location used by the connection.
-        """
-        for value in context.__dict__.values():
-            if not isinstance(value, Connection):
-                continue
-            if not isinstance(
-                    getattr(value.conn, '_ServerProxy__transport', None),
-                    SSLTransport):
-                continue
-            if hasattr(value.conn._ServerProxy__transport, 'dbdir'):
-                return value.conn._ServerProxy__transport.dbdir
-        return None
-
     def make_connection(self, host):
         host, self._extra_headers, _x509 = self.get_host_info(host)
 
         if self._connection and host == self._connection[0]:
             return self._connection[1]
 
-        dbdir = context.nss_dir
-        connection_dbdir = self.get_connection_dbdir()
+        ca_certfile = context.ca_certfile
 
-        if connection_dbdir:
-            # If an existing connection is already using the same NSS
-            # database there is no need to re-initialize.
-            no_init = dbdir == connection_dbdir
-
-        else:
-            # If the NSS database is already being used there is no
-            # need to re-initialize.
-            no_init = dbdir == ipapython.nsslib.current_dbdir
-
-        conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init,
-                             tls_version_min=api.env.tls_version_min,
-                             tls_version_max=api.env.tls_version_max)
-        self.dbdir=dbdir
+        conn = IPAHTTPSConnection(
+            host, 443, cafile=ca_certfile,
+            tls_version_min=api.env.tls_version_min,
+            tls_version_max=api.env.tls_version_max)
 
         conn.connect()
 
@@ -883,15 +855,15 @@ def apply_session_cookie(self, url):
         return session_url
 
     def create_connection(self, ccache=None, verbose=None, fallback=None,
-                          delegate=None, nss_dir=None):
+                          delegate=None, ca_certfile=None):
         if verbose is None:
             verbose = self.api.env.verbose
         if fallback is None:
             fallback = self.api.env.fallback
         if delegate is None:
             delegate = self.api.env.delegate
-        if nss_dir is None:
-            nss_dir = self.api.env.nss_dir
+        if ca_certfile is None:
+            ca_certfile = self.api.env.ca_certfile
         try:
             rpc_uri = self.env[self.env_rpc_uri_key]
             principal = get_principal()
@@ -903,7 +875,7 @@ def create_connection(self, ccache=None, verbose=None, fallback=None,
         except (errors.CCacheError, ValueError):
             # No session key, do full Kerberos auth
             pass
-        context.nss_dir = nss_dir
+        context.ca_certfile = ca_certfile
         urls = self.get_url_list(rpc_uri)
         serverproxy = None
         for url in urls:
@@ -1012,7 +984,7 @@ def forward(self, name, *args, **kw):
                 error=e.faultString,
                 server=server,
             )
-        except NSPRError as e:
+        except SSLError as e:
             raise NetworkError(uri=server, error=str(e))
         except ProtocolError as e:
             # By catching a 401 here we can detect the case where we have
@@ -1029,22 +1001,9 @@ def forward(self, name, *args, **kw):
                     # This shouldn't happen if we have a session but it isn't fatal.
                     pass
 
-                # Create a new serverproxy with the non-session URI. If there
-                # is an existing connection we need to save the NSS dbdir so
-                # we can skip an unnecessary NSS_Initialize() and avoid
-                # NSS_Shutdown issues.
+                # Create a new serverproxy with the non-session URI
                 serverproxy = self.create_connection(os.environ.get('KRB5CCNAME'), self.env.verbose, self.env.fallback, self.env.delegate)
-
-                dbdir = None
-                current_conn = getattr(context, self.id, None)
-                if current_conn is not None:
-                    dbdir = getattr(current_conn.conn._ServerProxy__transport, 'dbdir', None)
-                    if dbdir is not None:
-                        self.debug('Using dbdir %s' % dbdir)
                 setattr(context, self.id, Connection(serverproxy, self.disconnect))
-                if dbdir is not None:
-                    current_conn = getattr(context, self.id, None)
-                    current_conn.conn._ServerProxy__transport.dbdir = dbdir
                 return self.forward(name, *args, **kw)
             raise NetworkError(uri=server, error=e.errmsg)
         except socket.error as e:
diff --git a/ipalib/util.py b/ipalib/util.py
index 1c00cd7..e5b1aa1 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -33,6 +33,7 @@
 import dns
 import encodings
 import sys
+import ssl
 from weakref import WeakKeyDictionary
 
 import netaddr
@@ -42,6 +43,12 @@
 from netaddr.core import AddrFormatError
 import six
 
+try:
+    from httplib import HTTPSConnection
+except ImportError:
+    # Python 3
+    from http.client import HTTPSConnection
+
 from ipalib import errors, messages
 from ipalib.constants import DOMAIN_LEVEL_0
 from ipalib.text import _
@@ -51,6 +58,12 @@
 from ipapython.dnsutil import resolve_ip_addresses
 from ipapython.ipa_log_manager import root_logger
 
+try:
+    from ipaplatform.paths import paths
+    IPA_CA_CRT = paths.IPA_CA_CRT
+except ImportError:
+    IPA_CA_CRT = '/etc/ipa/ca.crt'
+
 if six.PY3:
     unicode = str
 
@@ -187,6 +200,88 @@ def normalize_zone(zone):
         return zone
 
 
+class IPAHTTPSConnection(HTTPSConnection, object):
+    """
+    This class inherits from `object` because HTTPSConnection does not in
+    Python 2.7. This is to allow the use of super() in its and derived
+    classes' methods.
+    """
+
+    # pylint: disable=no-member
+    tls_cutoff_map = {
+        "ssl2": ssl.OP_NO_SSLv2,
+        "tls1.0": ssl.OP_NO_TLSv1,
+        "tls1.1": ssl.OP_NO_TLSv1_1,
+        "tls1.2": ssl.OP_NO_TLSv1_2,
+    }
+    # pylint: enable=no-member
+
+    def __init__(self, host, port=HTTPSConnection.default_port,
+                 cafile=IPA_CA_CRT,
+                 client_certfile=None, client_keyfile=None,
+                 tls_version_min="tls1.1",
+                 tls_version_max="tls1.2",
+                 **kwargs):
+        """
+        Set up a client HTTPS connection.
+
+        :param host:  The host to connect to
+        :param port:  The port to connect to, defaults to
+                   HTTPSConnection.default_port
+        :param cafile:  A PEM-format file containning the trusted
+                        CA certificates
+        :param client_certfile:
+                A PEM-format client certificate file that will be used to
+                identificate the user to the server. It should also contain
+                the client private key.
+        :returns An established HTTPS connection to host:port
+        """
+        # pylint: disable=no-member
+        tls_cutoff = [
+            ssl.OP_NO_SSLv2,
+            ssl.OP_NO_TLSv1,
+            ssl.OP_NO_TLSv1_1,
+            ssl.OP_NO_TLSv1_2
+        ]
+        # remove the slice of negating protocol options according to options
+        min_idx = tls_cutoff.index(self.tls_cutoff_map[tls_version_min])
+        max_idx = tls_cutoff.index(self.tls_cutoff_map[tls_version_max])
+        tls_use = tls_cutoff[min_idx:max_idx+1]
+        del(tls_cutoff[min_idx:max_idx+1])
+
+        # official Python documentation states that the best option to get
+        # TLSv1 and later is to setup SSLContext with PROTOCOL_SSLv23
+        # and then negate the insecure SSLv2 and SSLv3
+        ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+        ctx.options |= (
+            ssl.OP_ALL | ssl.OP_NO_COMPRESSION | ssl.OP_SINGLE_DH_USE |
+            ssl.OP_SINGLE_ECDH_USE | ssl.OP_NO_SSLv3
+        )
+
+        # high ciphers without RC4, MD5, TripleDES, pre-shared key
+        # and secure remote password
+        ctx.set_ciphers("HIGH:!aNULL:!eNULL:!MD5:!RC4:!3DES:!PSK:!SRP")
+
+        # pylint: enable=no-member
+        for version in tls_cutoff:
+            ctx.options |= version
+
+        # make sure the given TLS version is available if Python decides to
+        # remove it from default TLS flags
+        for version in tls_use:
+            ctx.options &= ~version
+
+        ctx.verify_mode = ssl.CERT_REQUIRED
+        ctx.check_hostname = True
+        ctx.load_verify_locations(cafile)
+
+        if client_certfile is not None:
+            ctx.load_cert_chain(client_certfile)
+
+        super(IPAHTTPSConnection, self).__init__(host, port, context=ctx,
+                                                 **kwargs)
+
+
 def validate_dns_label(dns_label, allow_underscore=False, allow_slash=False):
     base_chars = 'a-z0-9'
     extra_chars = ''

From ad4cf6accfd6adacddf81967510c0cb8b76c97e6 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Mon, 2 Jan 2017 17:00:00 +0100
Subject: [PATCH 2/7] Move RA agent certificate file export to a different
 location

HTTPS connection to certificate server requires client authentication
so we need a file with client certificate and private key prior to
its first occurence which happens during migration of certificate
profiles to LDAP.

https://fedorahosted.org/freeipa/ticket/5695
https://fedorahosted.org/freeipa/ticket/6392
---
 install/restart_scripts/renew_ra_cert |  4 ++--
 ipaplatform/base/paths.py             |  2 +-
 ipaserver/install/cainstance.py       |  5 ++++-
 ipaserver/install/dogtaginstance.py   |  6 +++---
 ipaserver/install/ipa_backup.py       |  2 +-
 ipaserver/install/krainstance.py      |  7 +------
 ipaserver/install/server/upgrade.py   | 11 +++++------
 ipaserver/plugins/dogtag.py           |  2 +-
 8 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index d978f94..4dc6c2e 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -29,7 +29,7 @@ import traceback
 
 from ipalib.install.kinit import kinit_keytab
 from ipalib import api
-from ipaserver.install import certs, cainstance, krainstance
+from ipaserver.install import certs, cainstance, dogtaginstance
 from ipaplatform.paths import paths
 
 
@@ -61,7 +61,7 @@ def _main():
             cainstance.update_people_entry(dercert)
 
         if api.Command.kra_is_enabled()['result']:
-            krainstance.export_kra_agent_pem()
+            dogtaginstance.export_ra_agent_pem()
     finally:
         shutil.rmtree(tmpdir)
         api.Backend.ldap2.disconnect()
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index 896fa9d..d7f679a 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -135,7 +135,7 @@ class BasePathNamespace(object):
     ROOT_IPA_CACHE = "/root/.ipa_cache"
     ROOT_PKI = "/root/.pki"
     DOGTAG_ADMIN_P12 = "/root/ca-agent.p12"
-    KRA_AGENT_PEM = "/etc/httpd/alias/kra-agent.pem"
+    RA_AGENT_PEM = "/var/lib/ipa/ra-agent.pem"
     CACERT_P12 = "/root/cacert.p12"
     ROOT_IPA_CSR = "/root/ipa.csr"
     NAMED_PID = "/run/named/named.pid"
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index c7e81f0..e43adea 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -65,7 +65,8 @@
 from ipaserver.install import ldapupdate
 from ipaserver.install import replication
 from ipaserver.install import sysupgrade
-from ipaserver.install.dogtaginstance import DogtagInstance
+from ipaserver.install.dogtaginstance import (
+    DogtagInstance, export_ra_agent_pem)
 from ipaserver.plugins import ldap2
 
 # We need to reset the template because the CA uses the regular boot
@@ -413,6 +414,8 @@ def configure_instance(self, host_name, dm_password, admin_password,
                 else:
                     self.step("importing RA certificate from PKCS #12 file",
                               lambda: self.import_ra_cert(ra_p12))
+                self.step("exporting KRA agent cert", export_ra_agent_pem)
+
             if not ra_only:
                 self.step("importing CA chain to RA certificate database", self.__import_ca_chain)
                 self.step("setting up signing cert profile", self.__setup_sign_profile)
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index f4856c7..e6bbb39 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -74,11 +74,11 @@ def is_installing_replica(sys_type):
         return False
 
 
-def export_kra_agent_pem():
+def export_ra_agent_pem():
     """
     Export ipaCert with private key for client authentication.
     """
-    fd, filename = tempfile.mkstemp(dir=paths.HTTPD_ALIAS_DIR)
+    fd, filename = tempfile.mkstemp(dir=paths.VAR_LIB_IPA)
     os.close(fd)
 
     args = ["/usr/bin/pki",
@@ -92,7 +92,7 @@ def export_kra_agent_pem():
     os.chown(filename, 0, pent.pw_gid)
     os.chmod(filename, 0o440)
 
-    os.rename(filename, paths.KRA_AGENT_PEM)
+    os.rename(filename, paths.RA_AGENT_PEM)
 
 
 class DogtagInstance(service.Service):
diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
index c11120b..cf419ae 100644
--- a/ipaserver/install/ipa_backup.py
+++ b/ipaserver/install/ipa_backup.py
@@ -155,7 +155,7 @@ class Backup(admintool.AdminTool):
         paths.SMB_CONF,
         paths.SAMBA_KEYTAB,
         paths.DOGTAG_ADMIN_P12,
-        paths.KRA_AGENT_PEM,
+        paths.RA_AGENT_PEM,
         paths.CACERT_P12,
         paths.KRB5KDC_KDC_CONF,
         paths.SYSTEMD_IPA_SERVICE,
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index 554811c..b4f65fd 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -36,8 +36,7 @@
 from ipaserver.install import cainstance
 from ipaserver.install import installutils
 from ipaserver.install import ldapupdate
-from ipaserver.install.dogtaginstance import (export_kra_agent_pem,
-                                              DogtagInstance)
+from ipaserver.install.dogtaginstance import DogtagInstance
 from ipaserver.plugins import ldap2
 from ipapython.ipa_log_manager import log_mgr
 
@@ -115,7 +114,6 @@ def configure_instance(self, realm_name, host_name, dm_password,
             if not self.clone:
                 self.step("create KRA agent",
                           self.__create_kra_agent)
-        self.step("exporting KRA agent cert", export_kra_agent_pem)
         if not ra_only:
             if promote:
                 self.step("destroying installation admin user", self.teardown_admin)
@@ -272,9 +270,6 @@ def __spawn_instance(self):
             os.remove(cfg_file)
 
         shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12)
-
-        export_kra_agent_pem()
-
         self.log.debug("completed creating KRA instance")
 
     def __create_kra_agent(self):
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 5d8e596..fa6f17f 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -45,7 +45,6 @@
 from ipaserver.install import custodiainstance
 from ipaserver.install import sysupgrade
 from ipaserver.install import dnskeysyncinstance
-from ipaserver.install import krainstance
 from ipaserver.install import dogtaginstance
 from ipaserver.install import krbinstance
 from ipaserver.install import adtrustinstance
@@ -1416,10 +1415,10 @@ def fix_trust_flags():
     sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True)
 
 
-def export_kra_agent_pem():
+def export_ra_agent_pem():
     root_logger.info('[Exporting KRA agent PEM file]')
 
-    if sysupgrade.get_upgrade_state('http', 'export_kra_agent_pem'):
+    if sysupgrade.get_upgrade_state('http', 'export_ra_agent_pem'):
         root_logger.info("KRA agent PEM file already exported")
         return
 
@@ -1427,9 +1426,9 @@ def export_kra_agent_pem():
         root_logger.info("KRA is not enabled")
         return
 
-    krainstance.export_kra_agent_pem()
+    dogtaginstance.export_ra_agent_pem()
 
-    sysupgrade.set_upgrade_state('http', 'export_kra_agent_pem', True)
+    sysupgrade.set_upgrade_state('http', 'export_ra_agent_pem', True)
 
 
 def update_mod_nss_protocol(http):
@@ -1660,7 +1659,7 @@ def upgrade_configuration():
     update_mod_nss_protocol(http)
     update_mod_nss_cipher_suite(http)
     fix_trust_flags()
-    export_kra_agent_pem()
+    export_ra_agent_pem()
     http.start()
 
     uninstall_selfsign(ds, http)
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index 73c14ed..40b897d 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -2025,7 +2025,7 @@ def get_client(self):
             str(self.kra_port),
             'kra')
 
-        connection.set_authentication_cert(paths.KRA_AGENT_PEM)
+        connection.set_authentication_cert(paths.RA_AGENT_PEM)
 
         return KRAClient(connection, crypto)
 

From 24754900f16f2cc8a1518c0d047f2ac4a7c29988 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 4 Jan 2017 08:41:26 +0100
Subject: [PATCH 3/7] Don't run kra.configure_instance if not necessary

If kra should not be set up, don't run the code as it would only
prolong the installations.

Previously, krainstance configuration would be performed just to
export the client certificate and private key to authenticate to
certificate server. This is now performed somewhere else therefore
there's no need to run KRAInstance.configure_instance.

The kra.install() method still performs actions on replicas and
we're keeping it in server installer to conform to the installers
design.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipaserver/install/kra.py         | 16 +++++-----
 ipaserver/install/krainstance.py | 65 ++++++++++++++++++++--------------------
 2 files changed, 40 insertions(+), 41 deletions(-)

diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
index 0d1ed8e..7cfbae0 100644
--- a/ipaserver/install/kra.py
+++ b/ipaserver/install/kra.py
@@ -70,6 +70,8 @@ def install_check(api, replica_config, options):
 
 def install(api, replica_config, options):
     if replica_config is None:
+        if not options.setup_kra:
+            return
         realm_name = api.env.realm
         dm_password = options.dm_password
         host_name = api.env.host
@@ -77,7 +79,6 @@ def install(api, replica_config, options):
 
         pkcs12_info = None
         master_host = None
-        ra_only = not options.setup_kra
         promote = False
     else:
         krafile = os.path.join(replica_config.dir, 'kracert.p12')
@@ -97,6 +98,9 @@ def install(api, replica_config, options):
                     "  cacert.p12 file not found in replica file")
             shutil.copy(cafile, krafile)
 
+        if not replica_config.setup_kra:
+            return
+
         realm_name = replica_config.realm_name
         dm_password = replica_config.dirman_password
         host_name = replica_config.host_name
@@ -104,7 +108,6 @@ def install(api, replica_config, options):
 
         pkcs12_info = (krafile,)
         master_host = replica_config.kra_host_name
-        ra_only = not replica_config.setup_kra
         promote = options.promote
 
     kra = krainstance.KRAInstance(realm_name)
@@ -112,18 +115,15 @@ def install(api, replica_config, options):
                            subject_base=subject_base,
                            pkcs12_info=pkcs12_info,
                            master_host=master_host,
-                           ra_only=ra_only,
                            promote=promote)
 
     _service.print_msg("Restarting the directory server")
     ds = dsinstance.DsInstance()
     ds.restart()
+    kra.enable_client_auth_to_db(paths.KRA_CS_CFG_PATH)
 
-    if not ra_only:
-        kra.enable_client_auth_to_db(paths.KRA_CS_CFG_PATH)
-
-        # Restart apache for new proxy config file
-        services.knownservices.httpd.restart(capture_output=True)
+    # Restart apache for new proxy config file
+    services.knownservices.httpd.restart(capture_output=True)
 
 
 def uninstall(standalone):
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index b4f65fd..4735ff0 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -76,7 +76,7 @@ def __init__(self, realm):
 
     def configure_instance(self, realm_name, host_name, dm_password,
                            admin_password, pkcs12_info=None, master_host=None,
-                           subject_base=None, ra_only=False, promote=False):
+                           subject_base=None, promote=False):
         """Create a KRA instance.
 
            To create a clone, pass in pkcs12_info.
@@ -96,38 +96,37 @@ def configure_instance(self, realm_name, host_name, dm_password,
         self.realm = realm_name
         self.suffix = ipautil.realm_to_suffix(realm_name)
 
-        if not ra_only:
-            # Confirm that a KRA does not already exist
-            if self.is_installed():
-                raise RuntimeError(
-                    "KRA already installed.")
-            # Confirm that a Dogtag 10 CA instance already exists
-            ca = cainstance.CAInstance(self.realm, certs.NSS_DIR)
-            if not ca.is_installed():
-                raise RuntimeError(
-                    "KRA configuration failed.  "
-                    "A Dogtag CA must be installed first")
-
-            if promote:
-                self.step("creating installation admin user", self.setup_admin)
-            self.step("configuring KRA instance", self.__spawn_instance)
-            if not self.clone:
-                self.step("create KRA agent",
-                          self.__create_kra_agent)
-        if not ra_only:
-            if promote:
-                self.step("destroying installation admin user", self.teardown_admin)
-            self.step("restarting KRA", self.restart_instance)
-            self.step("configure certmonger for renewals",
-                      self.configure_certmonger_renewal)
-            self.step("configure certificate renewals", self.configure_renewal)
-            self.step("configure HTTP to proxy connections",
-                      self.http_proxy)
-            if not self.clone:
-                self.step("add vault container", self.__add_vault_container)
-            self.step("apply LDAP updates", self.__apply_updates)
-
-            self.step("enabling KRA instance", self.__enable_instance)
+        # Confirm that a KRA does not already exist
+        if self.is_installed():
+            raise RuntimeError(
+                "KRA already installed.")
+        # Confirm that a Dogtag 10 CA instance already exists
+        ca = cainstance.CAInstance(self.realm, certs.NSS_DIR)
+        if not ca.is_installed():
+            raise RuntimeError(
+                "KRA configuration failed.  "
+                "A Dogtag CA must be installed first")
+
+        if promote:
+            self.step("creating installation admin user", self.setup_admin)
+        self.step("configuring KRA instance", self.__spawn_instance)
+        if not self.clone:
+            self.step("create KRA agent",
+                      self.__create_kra_agent)
+        if promote:
+            self.step("destroying installation admin user",
+                      self.teardown_admin)
+        self.step("restarting KRA", self.restart_instance)
+        self.step("configure certmonger for renewals",
+                  self.configure_certmonger_renewal)
+        self.step("configure certificate renewals", self.configure_renewal)
+        self.step("configure HTTP to proxy connections",
+                  self.http_proxy)
+        if not self.clone:
+            self.step("add vault container", self.__add_vault_container)
+        self.step("apply LDAP updates", self.__apply_updates)
+
+        self.step("enabling KRA instance", self.__enable_instance)
 
         self.start_creation(runtime=126)
 

From 54b1f246859e8e392c5dd5d5de0e54ec94847e86 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 3 Jan 2017 09:49:48 +0100
Subject: [PATCH 4/7] Move publishing of CA cert to cainstance creation on
 master

IPAHTTPSConnection which is set up first time in certificate profiles
migration to LDAP requires CA cert to be stored in a file.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipaserver/install/cainstance.py     | 2 ++
 ipaserver/install/server/install.py | 6 +-----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index e43adea..42d3d28 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -422,6 +422,8 @@ def configure_instance(self, host_name, dm_password, admin_password,
                 self.step("setting audit signing renewal to 2 years", self.set_audit_renewal)
                 self.step("restarting certificate server", self.restart_instance)
                 if not self.clone:
+                    self.step("publishing the CA certificate",
+                              lambda: self.publish_ca_cert(paths.IPA_CA_CRT))
                     self.step("adding RA agent as a trusted user", self.__create_ca_agent)
                 self.step("authorizing RA to modify profiles", configure_profiles_acl)
                 self.step("authorizing RA to manage lightweight CAs",
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index fc319d9..03e5778 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -32,7 +32,7 @@
 )
 import ipaclient.install.ntpconf
 from ipaserver.install import (
-    bindinstance, ca, cainstance, certs, dns, dsinstance,
+    bindinstance, ca, certs, dns, dsinstance,
     httpinstance, installutils, kra, krbinstance, memcacheinstance,
     ntpinstance, otpdinstance, custodiainstance, replication, service,
     sysupgrade)
@@ -785,10 +785,6 @@ def install(installer):
             write_cache(cache_vars)
 
         ca.install_step_0(False, None, options)
-
-        # Now put the CA cert where other instances exepct it
-        ca_instance = cainstance.CAInstance(realm_name, certs.NSS_DIR)
-        ca_instance.publish_ca_cert(paths.IPA_CA_CRT)
     else:
         # Put the CA cert where other instances expect it
         x509.write_certificate(http_ca_cert, paths.IPA_CA_CRT)

From 4414fd3fa19e297ae2515e361f6afe714d018f6b Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 20 Dec 2016 10:23:47 +0100
Subject: [PATCH 5/7] Remove NSSConnection from Dogtag

Replaced NSSConnection with Python's httplib.HTTPSConnection.
This class is OpenSSL-based.

A client certificate with a private key is required to authenticate
against the certificate server. We facilitate the RA_AGENT_PEM which
already exists.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipapython/dogtag.py             | 20 +++++++-------------
 ipaserver/install/cainstance.py |  6 ------
 ipaserver/plugins/dogtag.py     | 39 +++++++++++++--------------------------
 3 files changed, 20 insertions(+), 45 deletions(-)

diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
index eb1f73e..ac757d5 100644
--- a/ipapython/dogtag.py
+++ b/ipapython/dogtag.py
@@ -20,16 +20,16 @@
 import collections
 import xml.dom.minidom
 
-import nss.nss as nss
 import six
 # pylint: disable=import-error
 from six.moves.urllib.parse import urlencode
 # pylint: enable=import-error
 
 from ipalib import api, errors
+from ipalib.util import IPAHTTPSConnection
 from ipalib.errors import NetworkError
 from ipalib.text import _
-from ipapython import nsslib, ipautil
+from ipapython import ipautil
 from ipapython.ipa_log_manager import root_logger
 
 # Python 3 rename. The package is available in "six.moves.http_client", but
@@ -131,8 +131,8 @@ def ca_status(ca_host=None):
     return _parse_ca_status(body)
 
 
-def https_request(host, port, url, secdir, password, nickname,
-        method='POST', headers=None, body=None, **kw):
+def https_request(host, port, url, cafile, client_certfile,
+                  method='POST', headers=None, body=None, **kw):
     """
     :param method: HTTP request method (defalut: 'POST')
     :param url: The path (not complete URL!) to post to.
@@ -145,15 +145,9 @@ def https_request(host, port, url, secdir, password, nickname,
     """
 
     def connection_factory(host, port):
-        no_init = secdir == nsslib.current_dbdir
-        conn = nsslib.NSSConnection(host, port, dbdir=secdir, no_init=no_init,
-                                    tls_version_min=api.env.tls_version_min,
-                                    tls_version_max=api.env.tls_version_max)
-        conn.set_debuglevel(0)
-        conn.connect()
-        conn.sock.set_client_auth_data_callback(
-            nsslib.client_auth_data_callback,
-            nickname, password, nss.get_default_certdb())
+        conn = IPAHTTPSConnection(host, port, cafile, client_certfile,
+                                  tls_version_min=api.env.tls_version_min,
+                                  tls_version_max=api.env.tls_version_max)
         return conn
 
     if body is None:
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 42d3d28..417ceb5 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1598,7 +1598,6 @@ def import_included_profiles():
         cn=['certprofiles'],
     )
 
-    api.Backend.ra_certprofile._read_password()
     api.Backend.ra_certprofile.override_port = 8443
 
     for (profile_id, desc, store_issued) in dogtag.INCLUDED_PROFILES:
@@ -1635,7 +1634,6 @@ def repair_profile_caIPAserviceCert():
     This function detects and repairs occurrences of this problem.
 
     """
-    api.Backend.ra_certprofile._read_password()
     api.Backend.ra_certprofile.override_port = 8443
 
     profile_id = 'caIPAserviceCert'
@@ -1678,8 +1676,6 @@ def migrate_profiles_to_ldap():
 
     """
     ensure_ldap_profiles_container()
-
-    api.Backend.ra_certprofile._read_password()
     api.Backend.ra_certprofile.override_port = 8443
 
     with open(paths.CA_CS_CFG_PATH) as f:
@@ -1764,8 +1760,6 @@ def ensure_ipa_authority_entry():
     """
 
     # find out authority id, issuer DN and subject DN of IPA CA
-    #
-    api.Backend.ra_lightweight_ca._read_password()
     api.Backend.ra_lightweight_ca.override_port = 8443
     with api.Backend.ra_lightweight_ca as lwca:
         data = lwca.read_ca('host-authority')
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index 40b897d..91da3a3 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -1238,29 +1238,18 @@ def _parse_dogtag_error(body):
 
     def __init__(self, api):
         if api.env.in_tree:
-            self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
-            self.pwd_file = self.sec_dir + os.sep + '.pwd'
+            self.ca_cert = os.path.join(api.env.dot_ipa, 'ca.crt')
+            self.client_certfile = os.path.join(
+                api.env.dot_ipa, 'ra-agent.pem')
         else:
-            self.sec_dir = paths.HTTPD_ALIAS_DIR
-            self.pwd_file = paths.ALIAS_PWDFILE_TXT
-        self.noise_file = self.sec_dir + os.sep + '.noise'
-        self.ipa_key_size = "2048"
-        self.ipa_certificate_nickname = "ipaCert"
-        self.ca_certificate_nickname = "caCert"
-        self._read_password()
+            self.ca_cert = paths.IPA_CA_CRT
+            self.client_certfile = paths.RA_AGENT_PEM
         super(RestClient, self).__init__(api)
 
         # session cookie
         self.override_port = None
         self.cookie = None
 
-    def _read_password(self):
-        try:
-            with open(self.pwd_file) as f:
-                self.password = f.readline().strip()
-        except IOError:
-            self.password = ''
-
     @cachedproperty
     def ca_host(self):
         """
@@ -1287,9 +1276,8 @@ def __enter__(self):
             return
         status, resp_headers, _resp_body = dogtag.https_request(
             self.ca_host, self.override_port or self.env.ca_agent_port,
-            '/ca/rest/account/login',
-            self.sec_dir, self.password, self.ipa_certificate_nickname,
-            method='GET'
+            '/ca/rest/account/login', self.ca_cert,
+            self.client_certfile, 'GET'
         )
         cookies = ipapython.cookie.Cookie.parse(resp_headers.get('set-cookie', ''))
         if status != 200 or len(cookies) == 0:
@@ -1301,9 +1289,8 @@ def __exit__(self, exc_type, exc_value, traceback):
         """Log out of the REST API"""
         dogtag.https_request(
             self.ca_host, self.override_port or self.env.ca_agent_port,
-            '/ca/rest/account/logout',
-            self.sec_dir, self.password, self.ipa_certificate_nickname,
-            method='GET'
+            '/ca/rest/account/logout', self.ca_cert,
+            self.client_certfile, 'GET'
         )
         self.cookie = None
 
@@ -1343,9 +1330,8 @@ def _ssldo(self, method, path, headers=None, body=None, use_session=True):
         # perform main request
         status, resp_headers, resp_body = dogtag.https_request(
             self.ca_host, self.override_port or self.env.ca_agent_port,
-            resource,
-            self.sec_dir, self.password, self.ipa_certificate_nickname,
-            method=method, headers=headers, body=body
+            resource, self.ca_cert, self.client_certfile,
+            method, headers, body
         )
         if status < 200 or status >= 300:
             explanation = self._parse_dogtag_error(resp_body) or ''
@@ -1425,7 +1411,8 @@ def _sslget(self, url, port, **kw):
 
         Perform an HTTPS request
         """
-        return dogtag.https_request(self.ca_host, port, url, self.sec_dir, self.password, self.ipa_certificate_nickname, **kw)
+        return dogtag.https_request(self.ca_host, port, url, self.ca_cert,
+                                    self.client_certfile, **kw)
 
     def get_parse_result_xml(self, xml_text, parse_func):
         '''

From 623d9d92f25c0708984b2038781e168b9ef1b389 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Tue, 3 Jan 2017 13:31:01 +0100
Subject: [PATCH 6/7] Remove NSSConnection from otptoken plugin

Replace NSSConnection with IPAHTTPSConnection to be able to remove
NSSConnection for good.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipaclient/plugins/otptoken.py | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/ipaclient/plugins/otptoken.py b/ipaclient/plugins/otptoken.py
index 885a612..1d57527 100644
--- a/ipaclient/plugins/otptoken.py
+++ b/ipaclient/plugins/otptoken.py
@@ -25,8 +25,8 @@
 from ipalib.messages import add_message, ResultFormattingError
 from ipalib.plugable import Registry
 from ipalib.frontend import Local
+from ipalib.util import IPAHTTPSConnection
 from ipapython.dn import DN
-from ipapython.nsslib import NSSConnection
 from ipapython.version import API_VERSION
 
 import locale
@@ -126,9 +126,7 @@ def __init__(self, **kwargs):
     def __inner(self, host, **kwargs):
         tmp = self.__kwargs.copy()
         tmp.update(kwargs)
-        # NSSConnection doesn't support timeout argument
-        tmp.pop('timeout', None)
-        return NSSConnection(host, **tmp)
+        return IPAHTTPSConnection(host, **tmp)
 
     def https_open(self, req):
         # pylint: disable=no-member
@@ -173,9 +171,10 @@ def forward(self, *args, **kwargs):
 
         # Sync the token.
         # pylint: disable=E1101
-        handler = HTTPSHandler(dbdir=api.env.nss_dir,
-                               tls_version_min=api.env.tls_version_min,
-                               tls_version_max=api.env.tls_version_max)
+        handler = HTTPSHandler(
+            cafile=api.env.ca_certfile,
+            tls_version_min=api.env.tls_version_min,
+            tls_version_max=api.env.tls_version_max)
         rsp = urllib.request.build_opener(handler).open(sync_uri, query)
         if rsp.getcode() == 200:
             status['result'][self.header] = rsp.info().get(self.header, 'unknown')

From 3f7107883c2628b9b15b7b3ed4e5906ef39d2651 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 4 Jan 2017 08:47:59 +0100
Subject: [PATCH 7/7] Remove ipapython.nsslib as it is not used anymore

Previous changes allowed the removal of nsslib.

So long, and thanks for all the fish.

https://fedorahosted.org/freeipa/ticket/5695
---
 ipapython/nsslib.py | 287 ----------------------------------------------------
 1 file changed, 287 deletions(-)
 delete mode 100644 ipapython/nsslib.py

diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py
deleted file mode 100644
index 08d05fc..0000000
--- a/ipapython/nsslib.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# Authors: Rob Crittenden <rcrit...@redhat.com>
-#          John Dennis <jden...@redhat.com>
-#
-# Copyright (C) 2009    Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import print_function
-
-import getpass
-import socket
-from ipapython.ipa_log_manager import root_logger
-
-from nss.error import NSPRError
-import nss.io as io
-import nss.nss as nss
-import nss.ssl as ssl
-import nss.error as error
-
-# Python 3 rename. The package is available in "six.moves.http_client", but
-# pylint cannot handle classes from that alias
-try:
-    import httplib
-except ImportError:
-    # pylint: disable=import-error
-    import http.client as httplib
-
-# NSS database currently open
-current_dbdir = None
-
-def auth_certificate_callback(sock, check_sig, is_server, certdb):
-    cert_is_valid = False
-
-    cert = sock.get_peer_certificate()
-
-    pin_args = sock.get_pkcs11_pin_arg()
-    if pin_args is None:
-        pin_args = ()
-
-    # Define how the cert is being used based upon the is_server flag.  This may
-    # seem backwards, but isn't. If we're a server we're trying to validate a
-    # client cert. If we're a client we're trying to validate a server cert.
-    if is_server:
-        intended_usage = nss.certificateUsageSSLClient
-    else:
-        intended_usage = nss.certificateUsageSSLServer
-
-    try:
-        # If the cert fails validation it will raise an exception, the errno attribute
-        # will be set to the error code matching the reason why the validation failed
-        # and the strerror attribute will contain a string describing the reason.
-        approved_usage = cert.verify_now(certdb, check_sig, intended_usage, *pin_args)
-    except Exception as e:
-        root_logger.error(
-            'cert validation failed for "%s" (%s)', cert.subject,
-            e.strerror)  # pylint: disable=no-member
-        cert_is_valid = False
-        return cert_is_valid
-
-    root_logger.debug("approved_usage = %s intended_usage = %s",
-                              ', '.join(nss.cert_usage_flags(approved_usage)),
-                              ', '.join(nss.cert_usage_flags(intended_usage)))
-
-    # Is the intended usage a proper subset of the approved usage
-    cert_is_valid = bool(approved_usage & intended_usage)
-
-    # If this is a server, we're finished
-    if is_server or not cert_is_valid:
-        root_logger.debug('cert valid %s for "%s"', cert_is_valid,  cert.subject)
-        return cert_is_valid
-
-    # Certificate is OK.  Since this is the client side of an SSL
-    # connection, we need to verify that the name field in the cert
-    # matches the desired hostname.  This is our defense against
-    # man-in-the-middle attacks.
-
-    hostname = sock.get_hostname()
-    try:
-        # If the cert fails validation it will raise an exception
-        cert_is_valid = cert.verify_hostname(hostname)
-    except Exception as e:
-        root_logger.error('failed verifying socket hostname "%s" matches cert subject "%s" (%s)',
-                          hostname, cert.subject,
-                          e.strerror)  # pylint: disable=no-member
-        cert_is_valid = False
-        return cert_is_valid
-
-    root_logger.debug('cert valid %s for "%s"', cert_is_valid,  cert.subject)
-    return cert_is_valid
-
-def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
-    cert = None
-    if chosen_nickname:
-        try:
-            cert = nss.find_cert_from_nickname(chosen_nickname, password)
-            priv_key = nss.find_key_by_any_cert(cert, password)
-            return cert, priv_key
-        except NSPRError:
-            return False
-    else:
-        nicknames = nss.get_cert_nicknames(certdb, nss.SEC_CERT_NICKNAMES_USER)
-        for nickname in nicknames:
-            try:
-                cert = nss.find_cert_from_nickname(nickname, password)
-                if cert.check_valid_times():
-                    if cert.has_signer_in_ca_names(ca_names):
-                        priv_key = nss.find_key_by_any_cert(cert, password)
-                        return cert, priv_key
-            except NSPRError:
-                return False
-        return False
-
-_af_dict = {
-    socket.AF_INET: io.PR_AF_INET,
-    socket.AF_INET6: io.PR_AF_INET6,
-    socket.AF_UNSPEC: io.PR_AF_UNSPEC
-}
-
-class NSSAddressFamilyFallback(object):
-    def __init__(self, family):
-        self.sock_family = family
-        self.family = self._get_nss_family(self.sock_family)
-
-    def _get_nss_family(self, sock_family):
-        """
-        Translate a family from python socket module to nss family.
-        """
-        try:
-            return _af_dict[sock_family]
-        except KeyError:
-            raise ValueError('Uknown socket family %d\n', sock_family)
-
-    def _create_socket(self):
-        self.sock = io.Socket(family=self.family)
-
-    def connect_socket(self, host, port):
-        try:
-            addr_info = io.AddrInfo(host, family=self.family)
-        except Exception:
-            raise NSPRError(
-                error_code=error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
-                error_message="Cannot resolve %s using family %s" % (host,
-                    io.addr_family_name(self.family)))
-
-        for net_addr in addr_info:
-            root_logger.debug("Connecting: %s", net_addr)
-            net_addr.port = port
-            self.family = net_addr.family
-            try:
-                self._create_socket()
-                self.sock.connect(net_addr)
-                return
-            except Exception as e:
-                root_logger.debug("Could not connect socket to %s, error: %s",
-                        net_addr, str(e))
-                root_logger.debug("Try to continue with next family...")
-                continue
-
-        raise NSPRError(
-            error_code=error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
-            error_message="Could not connect to %s using any address" % host)
-
-
-class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
-    default_port = httplib.HTTPSConnection.default_port
-
-    def __init__(self, host, port=None, strict=None,
-                 dbdir=None, family=socket.AF_UNSPEC, no_init=False,
-                 tls_version_min='tls1.1', tls_version_max='tls1.2'):
-        """
-        :param host: the server to connect to
-        :param port: the port to use (default is set in HTTPConnection)
-        :param dbdir: the NSS database directory
-        :param family: network family to use (default AF_UNSPEC)
-        :param no_init: do not initialize the NSS database. This requires
-                        that the database has already been initialized or
-                        the request will fail.
-        :param tls_min_version: mininum version of SSL/TLS supported
-        :param tls_max_version: maximum version of SSL/TLS supported.
-        """
-        httplib.HTTPConnection.__init__(self, host, port, strict)
-        NSSAddressFamilyFallback.__init__(self, family)
-
-        root_logger.debug('%s init %s', self.__class__.__name__, host)
-
-        # If initialization is requested, initialize the new database.
-        if not no_init:
-
-            if nss.nss_is_initialized():
-                ssl.clear_session_cache()
-                try:
-                    nss.nss_shutdown()
-                except NSPRError as e:
-                    if e.errno != error.SEC_ERROR_NOT_INITIALIZED:
-                        raise e
-
-            if not dbdir:
-                raise RuntimeError("dbdir is required")
-
-            nss.nss_init(dbdir)
-
-            global current_dbdir
-            current_dbdir = dbdir
-
-        ssl.set_domestic_policy()
-        nss.set_password_callback(self.password_callback)
-        self.tls_version_min = str(tls_version_min)
-        self.tls_version_max = str(tls_version_max)
-
-    def _create_socket(self):
-        ssl_enable_renegotiation = getattr(
-            ssl, 'SSL_ENABLE_RENEGOTIATION', 20)
-        ssl_require_safe_negotiation = getattr(
-            ssl,'SSL_REQUIRE_SAFE_NEGOTIATION', 21)
-        ssl_renegotiate_requires_xtn = getattr(
-            ssl, 'SSL_RENEGOTIATE_REQUIRES_XTN', 2)
-
-        # Create the socket here so we can do things like let the caller
-        # override the NSS callbacks
-        self.sock = ssl.SSLSocket(family=self.family)
-        self.sock.set_ssl_option(ssl.SSL_SECURITY, True)
-        self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True)
-        try:
-            self.sock.set_ssl_version_range(self.tls_version_min, self.tls_version_max)
-        except NSPRError:
-            root_logger.error('Failed to set TLS range to %s, %s' % (self.tls_version_min, self.tls_version_max))
-            raise
-        self.sock.set_ssl_option(ssl_require_safe_negotiation, False)
-        self.sock.set_ssl_option(ssl_enable_renegotiation, ssl_renegotiate_requires_xtn)
-        # Provide a callback which notifies us when the SSL handshake is complete
-        self.sock.set_handshake_callback(self.handshake_callback)
-
-        # Provide a callback to verify the servers certificate
-        self.sock.set_auth_certificate_callback(auth_certificate_callback,
-                                                nss.get_default_certdb())
-        self.sock.set_hostname(self.host)
-
-    def password_callback(self, slot, retry, password):
-        if not retry and password: return password
-        return getpass.getpass("Enter password for %s: " % slot.token_name)
-
-    def handshake_callback(self, sock):
-        """
-        Verify callback. If we get here then the certificate is ok.
-        """
-        channel = sock.get_ssl_channel_info()
-        suite = ssl.get_cipher_suite_info(channel.cipher_suite)
-        root_logger.debug("handshake complete, peer = %s", sock.get_peer_name())
-        root_logger.debug('Protocol: %s' % channel.protocol_version_str.upper())
-        root_logger.debug('Cipher: %s' % suite.cipher_suite_name)
-
-    def connect(self):
-        self.connect_socket(self.host, self.port)
-
-    def close(self):
-        """Close the connection to the HTTP server."""
-        if self.sock:
-            self.sock.close()   # close it manually... there may be other refs
-            self.sock = None
-            ssl.clear_session_cache()
-
-    def endheaders(self, message=None):
-        """
-        Explicitly close the connection if an error is returned after the
-        headers are sent. This will likely mean the initial SSL handshake
-        failed. If this isn't done then the connection is never closed and
-        subsequent NSS activities will fail with a BUSY error.
-        """
-        try:
-            # FIXME: httplib uses old-style classes so super doesn't work
-            httplib.HTTPConnection.endheaders(self, message)
-        except NSPRError as e:
-            self.close()
-            raise e
-- 
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