URL: https://github.com/freeipa/freeipa/pull/957
Author: rcritten
 Title: #957: Detect the backend crypto library that curl uses
Action: opened

PR body:
"""
In Fedora 27 curl is proposing to switch to using OpenSSL as
the crypto backend instead of NSS. This requires a new set of
arguments to certmonger to bootstrap fetching the IPA RA cert.

Debian/Ubuntu are still currently using an NSS-backed curl
so support both methods for now.

https://pagure.io/freeipa/issue/7076
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/957/head:pr957
git checkout pr957
From 3c7b8afa44df2998154ab58dee64227a1d5f1ebb Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Thu, 3 Aug 2017 17:49:44 -0400
Subject: [PATCH] Detect the backend crypto library that curl uses

In Fedora 27 curl is proposing to switch to using OpenSSL as
the crypto backend instead of NSS. This requires a new set of
arguments to certmonger to bootstrap fetching the IPA RA cert.

Debian/Ubuntu are still currently using an NSS-backed curl
so support both methods for now.

https://pagure.io/freeipa/issue/7076
---
 ipaserver/install/cainstance.py | 108 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 97 insertions(+), 11 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index b0e9e8757e..591c342400 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -811,13 +811,54 @@ def __export_ca_chain(self):
                     ipaca_pem.write('\n')
 
     def __request_ra_certificate(self):
-        # create a temp file storing the pwd
-        agent_file = tempfile.NamedTemporaryFile(
+        """
+        Request the IPA RA certificate from dogtag.
+
+        dogtag automatically generates an admin certificate that
+        in a usual deployment would be used in the UI to handle
+        administrative duties. IPA does not use this certificate
+        except as a bootstrap to generate the RA.
+
+        To do this it bends over backwards a bit by modifying the
+        way typical certificates are retrieved using certmonger by
+        forcing it to call dogtag-submit directly.
+
+        The switch of curl from NSS to OpenSSL complicates this a
+        little because the arguments to certmonger and the
+        certificate format differ. Screen scraping of the curl -V
+        output is used to determine the crypt library.  The output
+        format is loosely document at
+        http://curl.haxx.se/libcurl/c/curl_version_info.html
+
+        NOTE: we could also import python-pycurl and use
+        pycurl.version or pycurl.version_info() but the overhead of
+        a fork vs yet another package import seems worth it.
+        """
+        # Determine whether curl uses NSS or OpenSSL for crypto
+        result = ipautil.run(
+            [paths.BIN_CURL, '-V'],
+             raiseonerr=False,
+             capture_output=True)
+        if result.returncode == 0:
+            cryptolib = result.output.split()[4]
+        else:
+            raise RuntimeError(
+                'Unable to determine crypto engine curl uses: %s' % result)
+
+        # Note that this leaves the door open to use GnuTLS or another
+        # crypto backend that can use PEM files.
+        if 'NSS' in cryptolib:
+            use_nss = True
+        else:
+            use_nss = False
+
+        # create a temp file storing the agent password
+        agent_pwdfile = tempfile.NamedTemporaryFile(
             mode="w", dir=paths.VAR_LIB_IPA, delete=False)
-        agent_file.write(self.tmp_agent_pwd)
-        agent_file.close()
+        agent_pwdfile.write(self.tmp_agent_pwd)
+        agent_pwdfile.close()
 
-        # create a temp pem file storing the CA chain
+        # create a temp PEM file storing the CA chain
         chain_file = tempfile.NamedTemporaryFile(
             mode="w", dir=paths.VAR_LIB_IPA, delete=False)
         chain_file.close()
@@ -833,14 +874,56 @@ def __request_ra_certificate(self):
              "-out", chain_file.name,
              ], stdin=data, capture_output=False)
 
+        if not use_nss:
+            # Not NSS means we have to pass everything as PEM files.
+
+            # A temp PKCS#12 file storing the CA agent
+            agent_p12 = tempfile.NamedTemporaryFile(
+                mode="w", dir=paths.VAR_LIB_IPA, delete=False)
+            agent_p12.close()
+
+            # CA agent cert in PEM form
+            agent_cert = tempfile.NamedTemporaryFile(
+                mode="w", dir=paths.VAR_LIB_IPA, delete=False)
+            agent_cert.close()
+
+            # CA agent key in PEM form
+            agent_key = tempfile.NamedTemporaryFile(
+                mode="w", dir=paths.VAR_LIB_IPA, delete=False)
+            agent_key.close()
+            # Create a PKCS#12 file of the CA agent then extra the
+            # cert and key as discrete PEM files.
+            with open(agent_pwdfile.name) as f:
+                agent_pwd = f.read()
+
+            tmpdb = certs.CertDB(self.realm, nssdir=self.tmp_agent_db)
+            tmpdb.nssdb.pwd_file = agent_pwdfile.name
+            tmpdb.export_pkcs12(agent_p12.name,
+                                agent_pwdfile.name,
+                                "ipa-ca-agent")
+            certs.install_pem_from_p12(agent_p12.name,
+                                       agent_pwd,
+                                       agent_cert.name)
+            certs.install_key_from_p12(agent_p12.name,
+                                       agent_pwd,
+                                       agent_key.name)
+
         agent_args = [paths.CERTMONGER_DOGTAG_SUBMIT,
-                      "--dbdir", self.tmp_agent_db,
-                      "--nickname", "ipa-ca-agent",
                       "--cafile", chain_file.name,
                       "--ee-url", 'http://%s:8080/ca/ee/ca/' % self.fqdn,
                       "--agent-url",
-                      'https://%s:8443/ca/agent/ca/' % self.fqdn,
-                      "--sslpinfile", agent_file.name]
+                      'https://%s:8443/ca/agent/ca/' % self.fqdn,]
+
+        if use_nss:
+            backend_args = ["--dbdir", self.tmp_agent_db,
+                            "--nickname", "ipa-ca-agent",
+                            "--sslpinfile", agent_pwdfile.name,]
+        else:
+            backend_args = ["--certfile", agent_cert.name,
+                            "--keyfile", agent_key.name,]
+
+        agent_args += backend_args
+
         helper = " ".join(agent_args)
 
         # configure certmonger renew agent to use temporary agent cert
@@ -868,8 +951,11 @@ def __request_ra_certificate(self):
             # we can restore the helper parameters
             certmonger.modify_ca_helper(
                 ipalib.constants.RENEWAL_CA_NAME, old_helper)
-            # remove the pwdfile
-            for f in (agent_file, chain_file):
+            # remove any temporary files
+            files = (agent_pwdfile, chain_file)
+            if not use_nss:
+                files += (agent_p12, agent_cert, agent_key)
+            for f in files:
                 try:
                     os.remove(f.name)
                 except OSError:
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to