ccffd0
From a0626e09b3eaf5d030982e2ff03e95841ad1b4b9 Mon Sep 17 00:00:00 2001
ccffd0
From: Rob Crittenden <rcritten@redhat.com>
ccffd0
Date: Wed, 3 Feb 2021 15:52:05 -0500
ccffd0
Subject: [PATCH] ipa-cert-fix: Don't hardcode the NSS certificate nickname
ccffd0
ccffd0
The nickname of the 389-ds certificate was hardcoded as
ccffd0
Server-Cert which failed if the user had installed a
ccffd0
third-party certificate using ipa-server-certinstall.
ccffd0
ccffd0
Instead pull the nickname from the DS configuration and
ccffd0
retrieve it based on that.
ccffd0
ccffd0
https://pagure.io/freeipa/issue/8600
ccffd0
ccffd0
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
ccffd0
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
ccffd0
---
ccffd0
 ipaserver/install/ipa_cert_fix.py | 17 +++++++++++------
ccffd0
 1 file changed, 11 insertions(+), 6 deletions(-)
ccffd0
ccffd0
diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
ccffd0
index 2f2c15613..29af89cd5 100644
ccffd0
--- a/ipaserver/install/ipa_cert_fix.py
ccffd0
+++ b/ipaserver/install/ipa_cert_fix.py
ccffd0
@@ -203,9 +203,12 @@ def expired_ipa_certs(now):
ccffd0
         certs.append((IPACertType.HTTPS, cert))
ccffd0
 
ccffd0
     # LDAPS
ccffd0
-    ds_dbdir = dsinstance.config_dirname(realm_to_serverid(api.env.realm))
ccffd0
+    serverid = realm_to_serverid(api.env.realm)
ccffd0
+    ds = dsinstance.DsInstance(realm_name=api.env.realm)
ccffd0
+    ds_dbdir = dsinstance.config_dirname(serverid)
ccffd0
+    ds_nickname = ds.get_server_cert_nickname(serverid)
ccffd0
     db = NSSDatabase(nssdir=ds_dbdir)
ccffd0
-    cert = db.get_cert('Server-Cert')
ccffd0
+    cert = db.get_cert(ds_nickname)
ccffd0
     if cert.not_valid_after <= now:
ccffd0
         certs.append((IPACertType.LDAPS, cert))
ccffd0
 
ccffd0
@@ -344,11 +347,13 @@ def install_ipa_certs(subject_base, ca_subject_dn, certs):
ccffd0
         elif certtype is IPACertType.HTTPS:
ccffd0
             shutil.copyfile(cert_path, paths.HTTPD_CERT_FILE)
ccffd0
         elif certtype is IPACertType.LDAPS:
ccffd0
-            ds_dbdir = dsinstance.config_dirname(
ccffd0
-                realm_to_serverid(api.env.realm))
ccffd0
+            serverid = realm_to_serverid(api.env.realm)
ccffd0
+            ds = dsinstance.DsInstance(realm_name=api.env.realm)
ccffd0
+            ds_dbdir = dsinstance.config_dirname(serverid)
ccffd0
             db = NSSDatabase(nssdir=ds_dbdir)
ccffd0
-            db.delete_cert('Server-Cert')
ccffd0
-            db.import_pem_cert('Server-Cert', EMPTY_TRUST_FLAGS, cert_path)
ccffd0
+            ds_nickname = ds.get_server_cert_nickname(serverid)
ccffd0
+            db.delete_cert(ds_nickname)
ccffd0
+            db.import_pem_cert(ds_nickname, EMPTY_TRUST_FLAGS, cert_path)
ccffd0
         elif certtype is IPACertType.KDC:
ccffd0
             shutil.copyfile(cert_path, paths.KDC_CERT)
ccffd0
 
ccffd0
-- 
ccffd0
2.29.2
ccffd0
ccffd0
From 660507fda2394b17d709c47a05ce5df548a47990 Mon Sep 17 00:00:00 2001
ccffd0
From: Rob Crittenden <rcritten@redhat.com>
ccffd0
Date: Thu, 4 Feb 2021 08:25:48 -0500
ccffd0
Subject: [PATCH] ipatests: test third-party 389-ds cert with ipa-cert-fix
ccffd0
ccffd0
ipa-cert-fix was hardcoded to use Server-Cert as the nickname
ccffd0
so would fail if a third-party certificate was installed for DS.
ccffd0
ccffd0
https://pagure.io/freeipa/issue/8600
ccffd0
ccffd0
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
ccffd0
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
ccffd0
---
ccffd0
 .../test_integration/test_ipa_cert_fix.py     | 57 +++++++++++++++++++
ccffd0
 1 file changed, 57 insertions(+)
ccffd0
ccffd0
diff --git a/ipatests/test_integration/test_ipa_cert_fix.py b/ipatests/test_integration/test_ipa_cert_fix.py
ccffd0
index 2f7de5526..f9e5fe6e2 100644
ccffd0
--- a/ipatests/test_integration/test_ipa_cert_fix.py
ccffd0
+++ b/ipatests/test_integration/test_ipa_cert_fix.py
ccffd0
@@ -11,6 +11,17 @@ import time
ccffd0
 from ipaplatform.paths import paths
ccffd0
 from ipatests.pytest_ipa.integration import tasks
ccffd0
 from ipatests.test_integration.base import IntegrationTest
ccffd0
+from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
ccffd0
+
ccffd0
+
ccffd0
+def server_install_teardown(func):
ccffd0
+    def wrapped(*args):
ccffd0
+        master = args[0].master
ccffd0
+        try:
ccffd0
+            func(*args)
ccffd0
+        finally:
ccffd0
+            ipa_certs_cleanup(master)
ccffd0
+    return wrapped
ccffd0
 
ccffd0
 
ccffd0
 class TestIpaCertFix(IntegrationTest):
ccffd0
@@ -94,3 +105,49 @@ class TestIpaCertFix(IntegrationTest):
ccffd0
             else:
ccffd0
                 # timeout
ccffd0
                 raise AssertionError('Timeout: Failed to renew all the certs')
ccffd0
+
ccffd0
+
ccffd0
+class TestIpaCertFixThirdParty(CALessBase):
ccffd0
+    """
ccffd0
+    Test that ipa-cert-fix works with an installation with custom certs.
ccffd0
+    """
ccffd0
+
ccffd0
+    @classmethod
ccffd0
+    def install(cls, mh):
ccffd0
+        cls.nickname = 'ca1/server'
ccffd0
+
ccffd0
+        super(TestIpaCertFixThirdParty, cls).install(mh)
ccffd0
+        tasks.install_master(cls.master, setup_dns=True)
ccffd0
+
ccffd0
+    @server_install_teardown
ccffd0
+    def test_third_party_certs(self):
ccffd0
+        self.create_pkcs12(self.nickname,
ccffd0
+                           password=self.cert_password,
ccffd0
+                           filename='server.p12')
ccffd0
+        self.prepare_cacert('ca1')
ccffd0
+
ccffd0
+        # We have a chain length of one. If this is extended then the
ccffd0
+        # additional cert names will need to be calculated.
ccffd0
+        nick_chain = self.nickname.split('/')
ccffd0
+        ca_cert = '%s.crt' % nick_chain[0]
ccffd0
+
ccffd0
+        # Add the CA to the IPA store
ccffd0
+        self.copy_cert(self.master, ca_cert)
ccffd0
+        self.master.run_command(['ipa-cacert-manage', 'install', ca_cert])
ccffd0
+
ccffd0
+        # Apply the new cert chain otherwise ipa-server-certinstall will fail
ccffd0
+        self.master.run_command(['ipa-certupdate'])
ccffd0
+
ccffd0
+        # Install the updated certs and restart the world
ccffd0
+        self.copy_cert(self.master, 'server.p12')
ccffd0
+        args = ['ipa-server-certinstall',
ccffd0
+                '-p', self.master.config.dirman_password,
ccffd0
+                '--pin', self.master.config.admin_password,
ccffd0
+                '-d', 'server.p12']
ccffd0
+        self.master.run_command(args)
ccffd0
+        self.master.run_command(['ipactl', 'restart',])
ccffd0
+
ccffd0
+        # Run ipa-cert-fix. This is basically a no-op but tests that
ccffd0
+        # the DS nickname is used and not a hardcoded value.
ccffd0
+        result = self.master.run_command(['ipa-cert-fix', '-v'],)
ccffd0
+        assert self.nickname in result.stderr_text
ccffd0
-- 
ccffd0
2.29.2
ccffd0
ccffd0
From 4cb6f0ba0df928eea60b20892a6fc85373627946 Mon Sep 17 00:00:00 2001
ccffd0
From: Rob Crittenden <rcritten@redhat.com>
ccffd0
Date: Fri, 5 Feb 2021 09:00:54 -0500
ccffd0
Subject: [PATCH] Set pki-core dependency to 10.3.3 for pki-server cert-fix bug
ccffd0
ccffd0
Related: https://github.com/dogtagpki/pki/issues/3387
ccffd0
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
ccffd0
---
ccffd0
 freeipa.spec.in | 4 ++--
ccffd0
 1 file changed, 2 insertions(+), 2 deletions(-)
ccffd0
ccffd0
diff --git a/freeipa.spec.in b/freeipa.spec.in
ccffd0
index 93e473ac4..0e261285b 100755
ccffd0
--- a/freeipa.spec.in
ccffd0
+++ b/freeipa.spec.in
ccffd0
@@ -128,11 +128,11 @@
ccffd0
 %if 0%{?rhel} == 8
ccffd0
 # PKIConnection has been modified to always validate certs.
ccffd0
 # https://pagure.io/freeipa/issue/8379
ccffd0
-%global pki_version 10.9.0-0.4
ccffd0
+%global pki_version 10.10.4-1
ccffd0
 %else
ccffd0
 # New KRA profile, ACME support
ccffd0
 # https://pagure.io/freeipa/issue/8545
ccffd0
-%global pki_version 10.10.0-2
ccffd0
+%global pki_version 10.10.3-1
ccffd0
 %endif
ccffd0
 
ccffd0
 # RHEL 8.3+, F32+ has 0.79.13
ccffd0
-- 
ccffd0
2.29.2
ccffd0
ccffd0
From f3463728f2196589d36e14cedccb26c03730a7c0 Mon Sep 17 00:00:00 2001
ccffd0
From: Rob Crittenden <rcritten@redhat.com>
ccffd0
Date: Wed, 10 Feb 2021 16:07:13 -0500
ccffd0
Subject: [PATCH] Don't renew non-IPA issued certs in ipa-cert-fix
ccffd0
ccffd0
If the Apache, 389-ds or KDC certificate was issued by
ccffd0
a third party there is nothing we can do, regardless of
ccffd0
whether it is expired or not.
ccffd0
ccffd0
Report which certificates will not be renewed so the
ccffd0
admin can manually do do (likely in the event of a
ccffd0
third-party certificate).
ccffd0
ccffd0
https://pagure.io/freeipa/issue/8600
ccffd0
ccffd0
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
ccffd0
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
ccffd0
---
ccffd0
 ipaserver/install/ipa_cert_fix.py | 53 +++++++++++++++++++++++++------
ccffd0
 1 file changed, 43 insertions(+), 10 deletions(-)
ccffd0
ccffd0
diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
ccffd0
index 29af89cd5..210cf80f1 100644
ccffd0
--- a/ipaserver/install/ipa_cert_fix.py
ccffd0
+++ b/ipaserver/install/ipa_cert_fix.py
ccffd0
@@ -43,6 +43,7 @@ from ipapython.certdb import NSSDatabase, EMPTY_TRUST_FLAGS
ccffd0
 from ipapython.dn import DN
ccffd0
 from ipapython.ipaldap import realm_to_serverid
ccffd0
 from ipaserver.install import ca, cainstance, dsinstance
ccffd0
+from ipaserver.install.certs import is_ipa_issued_cert
ccffd0
 from ipapython import directivesetter
ccffd0
 from ipapython import ipautil
ccffd0
 
ccffd0
@@ -104,6 +105,13 @@ class IPACertFix(AdminTool):
ccffd0
 
ccffd0
         api.bootstrap(in_server=True, confdir=paths.ETC_IPA)
ccffd0
         api.finalize()
ccffd0
+
ccffd0
+        if not dsinstance.is_ds_running(realm_to_serverid(api.env.realm)):
ccffd0
+            print(
ccffd0
+                "The LDAP server is not running; cannot proceed."
ccffd0
+            )
ccffd0
+            return 1
ccffd0
+
ccffd0
         api.Backend.ldap2.connect()  # ensure DS is up
ccffd0
 
ccffd0
         subject_base = dsinstance.DsInstance().find_subject_base()
ccffd0
@@ -113,7 +121,7 @@ class IPACertFix(AdminTool):
ccffd0
         ca_subject_dn = ca.lookup_ca_subject(api, subject_base)
ccffd0
 
ccffd0
         now = datetime.datetime.now() + datetime.timedelta(weeks=2)
ccffd0
-        certs, extra_certs = expired_certs(now)
ccffd0
+        certs, extra_certs, non_renewed = expired_certs(now)
ccffd0
 
ccffd0
         if not certs and not extra_certs:
ccffd0
             print("Nothing to do.")
ccffd0
@@ -121,7 +129,7 @@ class IPACertFix(AdminTool):
ccffd0
 
ccffd0
         print(msg)
ccffd0
 
ccffd0
-        print_intentions(certs, extra_certs)
ccffd0
+        print_intentions(certs, extra_certs, non_renewed)
ccffd0
 
ccffd0
         response = ipautil.user_input('Enter "yes" to proceed')
ccffd0
         if response.lower() != 'yes':
ccffd0
@@ -133,7 +141,10 @@ class IPACertFix(AdminTool):
ccffd0
             fix_certreq_directives(certs)
ccffd0
             run_cert_fix(certs, extra_certs)
ccffd0
         except ipautil.CalledProcessError:
ccffd0
-            if any(x[0] is IPACertType.LDAPS for x in extra_certs):
ccffd0
+            if any(
ccffd0
+                x[0] is IPACertType.LDAPS
ccffd0
+                for x in extra_certs + non_renewed
ccffd0
+            ):
ccffd0
                 # The DS cert was expired.  This will cause
ccffd0
                 # 'pki-server cert-fix' to fail at the final
ccffd0
                 # restart.  Therefore ignore the CalledProcessError
ccffd0
@@ -152,13 +163,15 @@ class IPACertFix(AdminTool):
ccffd0
             print("Becoming renewal master.")
ccffd0
             cainstance.CAInstance().set_renewal_master()
ccffd0
 
ccffd0
+        print("Restarting IPA")
ccffd0
         ipautil.run(['ipactl', 'restart'], raiseonerr=True)
ccffd0
 
ccffd0
         return 0
ccffd0
 
ccffd0
 
ccffd0
 def expired_certs(now):
ccffd0
-    return expired_dogtag_certs(now), expired_ipa_certs(now)
ccffd0
+    expired_ipa, non_renew_ipa = expired_ipa_certs(now)
ccffd0
+    return expired_dogtag_certs(now), expired_ipa, non_renew_ipa
ccffd0
 
ccffd0
 
ccffd0
 def expired_dogtag_certs(now):
ccffd0
@@ -191,6 +204,7 @@ def expired_ipa_certs(now):
ccffd0
 
ccffd0
     """
ccffd0
     certs = []
ccffd0
+    non_renewed = []
ccffd0
 
ccffd0
     # IPA RA
ccffd0
     cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
ccffd0
@@ -200,7 +214,10 @@ def expired_ipa_certs(now):
ccffd0
     # Apache HTTPD
ccffd0
     cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
ccffd0
     if cert.not_valid_after <= now:
ccffd0
-        certs.append((IPACertType.HTTPS, cert))
ccffd0
+        if not is_ipa_issued_cert(api, cert):
ccffd0
+            non_renewed.append((IPACertType.HTTPS, cert))
ccffd0
+        else:
ccffd0
+            certs.append((IPACertType.HTTPS, cert))
ccffd0
 
ccffd0
     # LDAPS
ccffd0
     serverid = realm_to_serverid(api.env.realm)
ccffd0
@@ -210,18 +227,24 @@ def expired_ipa_certs(now):
ccffd0
     db = NSSDatabase(nssdir=ds_dbdir)
ccffd0
     cert = db.get_cert(ds_nickname)
ccffd0
     if cert.not_valid_after <= now:
ccffd0
-        certs.append((IPACertType.LDAPS, cert))
ccffd0
+        if not is_ipa_issued_cert(api, cert):
ccffd0
+            non_renewed.append((IPACertType.LDAPS, cert))
ccffd0
+        else:
ccffd0
+            certs.append((IPACertType.LDAPS, cert))
ccffd0
 
ccffd0
     # KDC
ccffd0
     cert = x509.load_certificate_from_file(paths.KDC_CERT)
ccffd0
     if cert.not_valid_after <= now:
ccffd0
-        certs.append((IPACertType.KDC, cert))
ccffd0
+        if not is_ipa_issued_cert(api, cert):
ccffd0
+            non_renewed.append((IPACertType.HTTPS, cert))
ccffd0
+        else:
ccffd0
+            certs.append((IPACertType.KDC, cert))
ccffd0
 
ccffd0
-    return certs
ccffd0
+    return certs, non_renewed
ccffd0
 
ccffd0
 
ccffd0
-def print_intentions(dogtag_certs, ipa_certs):
ccffd0
-    print("The following certificates will be renewed: ")
ccffd0
+def print_intentions(dogtag_certs, ipa_certs, non_renewed):
ccffd0
+    print("The following certificates will be renewed:")
ccffd0
     print()
ccffd0
 
ccffd0
     for certid, cert in dogtag_certs:
ccffd0
@@ -230,6 +253,16 @@ def print_intentions(dogtag_certs, ipa_certs):
ccffd0
     for certtype, cert in ipa_certs:
ccffd0
         print_cert_info("IPA", certtype.value, cert)
ccffd0
 
ccffd0
+    if non_renewed:
ccffd0
+        print(
ccffd0
+            "The following certificates will NOT be renewed because "
ccffd0
+            "they were not issued by the IPA CA:"
ccffd0
+        )
ccffd0
+        print()
ccffd0
+
ccffd0
+        for certtype, cert in non_renewed:
ccffd0
+            print_cert_info("IPA", certtype.value, cert)
ccffd0
+
ccffd0
 
ccffd0
 def print_cert_info(context, desc, cert):
ccffd0
     print("{} {} certificate:".format(context, desc))
ccffd0
-- 
ccffd0
2.29.2
ccffd0