Blob Blame History Raw
From 6a30753c5a437240e4678ef4acae3255ad6d15ee Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Mon, 24 Apr 2017 06:40:11 +0000
Subject: [PATCH] renew agent: get rid of virtual profiles

Replace all uses of virtual profiles with `dogtag-ipa-ca-renew-agent-reuse`
and remove profile from the IPA CA certificate tracking request.

This prevents virtual profiles from making their way into CSRs and in turn
being rejected by certain CAs. This affected the IPA CA CSR with Microsoft
CS in particular.

https://pagure.io/freeipa/issue/5799

Reviewed-By: David Kupka <dkupka@redhat.com>
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
---
 .../certmonger/dogtag-ipa-ca-renew-agent-submit    | 50 ++++------------------
 ipaclient/install/ipa_certupdate.py                |  4 +-
 ipalib/install/certmonger.py                       | 25 ++++++++---
 ipaserver/install/cainstance.py                    |  8 ++--
 ipaserver/install/dogtaginstance.py                |  6 +--
 ipaserver/install/ipa_cacert_manage.py             | 12 +++---
 ipaserver/install/krainstance.py                   |  6 +--
 ipaserver/install/server/upgrade.py                |  2 +-
 8 files changed, 46 insertions(+), 67 deletions(-)

diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
index 657a1bc638e1da680522c638e92914098fc6ab4b..3d3e791449014082060ecdc50118a28a9ef315b8 100755
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
@@ -297,7 +297,7 @@ def store_cert(**kwargs):
             syslog.syslog(
                 syslog.LOG_ERR,
                 "Giving up. To retry storing the certificate, resubmit the "
-                "request with profile \"ipaStorage\"")
+                "request with CA \"dogtag-ipa-ca-renew-agent-reuse\"")
 
     return (ISSUED, cert)
 
@@ -420,33 +420,6 @@ def retrieve_cert(**kwargs):
     return result
 
 
-def export_csr(**kwargs):
-    """
-    This does not actually renew the cert, it just writes the CSR provided
-    by certmonger to /var/lib/ipa/ca.csr and returns the existing cert.
-    """
-    operation = os.environ.get('CERTMONGER_OPERATION')
-    if operation != 'SUBMIT':
-        return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
-
-    csr = os.environ.get('CERTMONGER_CSR')
-    if not csr:
-        return (UNCONFIGURED, "Certificate request not provided")
-
-    cert = os.environ.get('CERTMONGER_CERTIFICATE')
-    if not cert:
-        return (REJECTED, "New certificate requests not supported")
-
-    csr_file = paths.IPA_CA_CSR
-    try:
-        with open(csr_file, 'wb') as f:
-            f.write(csr)
-    except Exception as e:
-        return (UNREACHABLE, "Failed to write %s: %s" % (csr_file, e))
-
-    return (ISSUED, cert)
-
-
 def renew_ca_cert(reuse_existing, **kwargs):
     """
     This is used for automatic CA certificate renewal.
@@ -497,12 +470,15 @@ def renew_ca_cert(reuse_existing, **kwargs):
                           "use ipa-cacert-manage to renew it"
                           % (os.environ.get("CERTMONGER_REQ_SUBJECT"),))
     elif state == 'request':
-        profile = os.environ['CERTMONGER_CA_PROFILE']
+        profile = os.environ.get('CERTMONGER_CA_PROFILE')
         os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert'
         result = call_handler(request_and_store_cert,
                               reuse_existing=reuse_existing,
                               **kwargs)
-        os.environ['CERTMONGER_CA_PROFILE'] = profile
+        if profile is not None:
+            os.environ['CERTMONGER_CA_PROFILE'] = profile
+        else:
+            del os.environ['CERTMONGER_CA_PROFILE']
 
     if result[0] == WAIT:
         return (result[0], '%s:%s' % (state, result[1]))
@@ -522,14 +498,6 @@ def main():
     else:
         kwargs['reuse_existing'] = True
 
-    handlers = {
-        'ipaStorage':           store_cert,
-        'ipaRetrievalOrReuse':  retrieve_or_reuse_cert,
-        'ipaRetrieval':         retrieve_cert,
-        'ipaCSRExport':         export_csr,
-        'ipaCACertRenewal':     renew_ca_cert,
-    }
-
     api.bootstrap(in_server=True, context='renew', confdir=paths.ETC_IPA)
     api.finalize()
 
@@ -547,15 +515,15 @@ def main():
 
         api.Backend.ldap2.connect()
 
-        profile = os.environ.get('CERTMONGER_CA_PROFILE')
-        if is_replicated():
+        if get_nickname() == IPA_CA_NICKNAME:
+            handler = renew_ca_cert
+        elif is_replicated():
             if is_renewal_master():
                 handler = request_and_store_cert
             else:
                 handler = retrieve_cert_continuous
         else:
             handler = request_cert
-        handler = handlers.get(profile, handler)
 
         res = call_handler(handler, **kwargs)
         for item in res[1:]:
diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
index d6ffbde1900280b548877752726e4f066632877a..7dc88f07ae14e5416f6fe3dc8400b7d4bcabef72 100644
--- a/ipaclient/install/ipa_certupdate.py
+++ b/ipaclient/install/ipa_certupdate.py
@@ -153,7 +153,7 @@ class CertUpdate(admintool.AdminTool):
 
             self.log.debug("resubmitting certmonger request '%s'", request_id)
             certmonger.resubmit_request(
-                request_id, profile='ipaRetrievalOrReuse')
+                request_id, ca='dogtag-ipa-ca-renew-agent-reuse', profile='')
             try:
                 state = certmonger.wait_for_request(request_id, timeout)
             except RuntimeError:
@@ -167,7 +167,7 @@ class CertUpdate(admintool.AdminTool):
                     "please check the request manually" % request_id)
 
             self.log.debug("modifying certmonger request '%s'", request_id)
-            certmonger.modify(request_id, profile='ipaCACertRenewal')
+            certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent')
 
         self.update_file(paths.CA_CRT, certs)
 
diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py
index 2a7876ea9ba986f57c00fc7ad61d10fe91894f55..5709853ffebdbf58929b9a935e906ae67341bea8 100644
--- a/ipalib/install/certmonger.py
+++ b/ipalib/install/certmonger.py
@@ -501,18 +501,29 @@ def stop_tracking(secdir=None, request_id=None, nickname=None, certfile=None):
         request.parent.obj_if.remove_request(request.path)
 
 
-def modify(request_id, profile=None):
-    if profile:
+def modify(request_id, ca=None, profile=None):
+    if ca or profile:
         request = _get_request({'nickname': request_id})
-        if request:
-            request.obj_if.modify({'template-profile': profile})
+        update = {}
+        if ca is not None:
+            cm = _certmonger()
+            update['CA'] = cm.obj_if.find_ca_by_nickname(ca)
+        if profile is not None:
+            update['template-profile'] = profile
+        request.obj_if.modify(update)
 
 
-def resubmit_request(request_id, profile=None):
+def resubmit_request(request_id, ca=None, profile=None):
     request = _get_request({'nickname': request_id})
     if request:
-        if profile:
-            request.obj_if.modify({'template-profile': profile})
+        if ca or profile:
+            update = {}
+            if ca is not None:
+                cm = _certmonger()
+                update['CA'] = cm.obj_if.find_ca_by_nickname(ca)
+            if profile is not None:
+                update['template-profile'] = profile
+            request.obj_if.modify(update)
         request.obj_if.resubmit()
 
 
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index ff5432d1a7460f1b853c7cf7490b3604c82cd1f7..a4aa4f2069277181501ebd92f3795c452b10acd0 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -279,10 +279,10 @@ class CAInstance(DogtagInstance):
        2 = have signed cert, continue installation
     """
 
-    tracking_reqs = (('auditSigningCert cert-pki-ca', None),
-                     ('ocspSigningCert cert-pki-ca', None),
-                     ('subsystemCert cert-pki-ca', None),
-                     ('caSigningCert cert-pki-ca', 'ipaCACertRenewal'))
+    tracking_reqs = ('auditSigningCert cert-pki-ca',
+                     'ocspSigningCert cert-pki-ca',
+                     'subsystemCert cert-pki-ca',
+                     'caSigningCert cert-pki-ca')
     server_cert_name = 'Server-Cert cert-pki-ca'
 
     def __init__(self, realm=None, host_name=None):
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index e0515973f7a598b30c6f12675b9ebdbfd0cf3423..3ba13815055612c5fff44831c8f874e6175d94cd 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -287,7 +287,7 @@ class DogtagInstance(service.Service):
         """ Configure certmonger to renew system certs """
         pin = self.__get_pin()
 
-        for nickname, profile in self.tracking_reqs:
+        for nickname in self.tracking_reqs:
             try:
                 certmonger.start_tracking(
                     certpath=self.nss_db,
@@ -296,7 +296,7 @@ class DogtagInstance(service.Service):
                     pin=pin,
                     pre_command='stop_pkicad',
                     post_command='renew_ca_cert "%s"' % nickname,
-                    profile=profile)
+                )
             except RuntimeError as e:
                 self.log.error(
                     "certmonger failed to start tracking certificate: %s", e)
@@ -331,7 +331,7 @@ class DogtagInstance(service.Service):
         services.knownservices.messagebus.start()
         cmonger.start()
 
-        nicknames = [nickname for nickname, _profile in self.tracking_reqs]
+        nicknames = self.tracking_reqs
         if self.server_cert_name is not None:
             nicknames.append(self.server_cert_name)
 
diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py
index 363ba378ab206fae5c220b754f212666f20384af..6d28c62b36b3909c9a3d95a5c6c84d1779fe4c33 100644
--- a/ipaserver/install/ipa_cacert_manage.py
+++ b/ipaserver/install/ipa_cacert_manage.py
@@ -172,14 +172,14 @@ class CACertManage(admintool.AdminTool):
         except errors.NotFound:
             raise admintool.ScriptError("CA renewal master not found")
 
-        self.resubmit_request(ca, 'caCACert')
+        self.resubmit_request()
 
         print("CA certificate successfully renewed")
 
     def renew_external_step_1(self, ca):
         print("Exporting CA certificate signing request, please wait")
 
-        self.resubmit_request(ca, 'ipaCSRExport')
+        self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse')
 
         print(("The next step is to get %s signed by your CA and re-run "
               "ipa-cacert-manage as:" % paths.IPA_CA_CSR))
@@ -282,15 +282,15 @@ class CACertManage(admintool.AdminTool):
         except errors.NotFound:
             raise admintool.ScriptError("CA renewal master not found")
 
-        self.resubmit_request(ca, 'ipaRetrieval')
+        self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse')
 
         print("CA certificate successfully renewed")
 
-    def resubmit_request(self, ca, profile):
+    def resubmit_request(self, ca='dogtag-ipa-ca-renew-agent'):
         timeout = api.env.startup_timeout + 60
 
         self.log.debug("resubmitting certmonger request '%s'", self.request_id)
-        certmonger.resubmit_request(self.request_id, profile=profile)
+        certmonger.resubmit_request(self.request_id, ca=ca, profile='')
         try:
             state = certmonger.wait_for_request(self.request_id, timeout)
         except RuntimeError:
@@ -304,7 +304,7 @@ class CACertManage(admintool.AdminTool):
                 "please check the request manually" % self.request_id)
 
         self.log.debug("modifying certmonger request '%s'", self.request_id)
-        certmonger.modify(self.request_id, profile='ipaCACertRenewal')
+        certmonger.modify(self.request_id, ca='dogtag-ipa-ca-renew-agent')
 
     def install(self):
         print("Installing CA certificate, please wait")
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index c39d6874a9d685f91b5d30ea1954320b8ee0c1ed..abb81897a404613e20be10d348096402ef08624b 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -60,9 +60,9 @@ class KRAInstance(DogtagInstance):
     be the same for both the CA and KRA.
     """
 
-    tracking_reqs = (('auditSigningCert cert-pki-kra', None),
-                     ('transportCert cert-pki-kra', None),
-                     ('storageCert cert-pki-kra', None))
+    tracking_reqs = ('auditSigningCert cert-pki-kra',
+                     'transportCert cert-pki-kra',
+                     'storageCert cert-pki-kra')
 
     def __init__(self, realm):
         super(KRAInstance, self).__init__(
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 96fdadf751ef619e198a861d9f62440c98f3abae..5e5c83731d3d3415deb61271baa7865c62f60336 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -937,7 +937,7 @@ def certificate_renewal_update(ca, ds, http):
             'cert-presave-command': template % 'stop_pkicad',
             'cert-postsave-command':
                 (template % 'renew_ca_cert "caSigningCert cert-pki-ca"'),
-            'template-profile': 'ipaCACertRenewal',
+            'template-profile': '',
         },
         {
             'cert-database': paths.PKI_TOMCAT_ALIAS_DIR,
-- 
2.9.3