URL: https://github.com/freeipa/freeipa/pull/2057
Author: tiran
 Title: #2057: Ensure that public cert and CA bundle are readable
Action: opened

PR body:
"""
In CIS hardened mode, the process umask is 027. This results in some
files not being world readable. Ensure that write_certificate_list()
calls in client installer, server installer, and upgrader create cert
bundles with permission bits 0644.

Make CA bundles, certs, and cert directories world-accessible in
upgrader.

Fixes: pagure.io/freeipa/issue/7594
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/2057/head:pr2057
git checkout pr2057
From d35680f5d41417c1e20c27bba8ff0747b916e38d Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Fri, 22 Jun 2018 12:17:23 +0200
Subject: [PATCH 1/4] Ensure that public cert and CA bundle are readable

In CIS hardened mode, the process umask is 027. This results in some
files not being world readable. Ensure that write_certificate_list()
calls in client installer, server installer, and upgrader create cert
bundles with permission bits 0644.

Fixes: https://pagure.io/freeipa/issue/7594
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaclient/install/client.py                | 10 +++++++---
 ipaclient/install/ipa_certupdate.py        |  4 ++--
 ipalib/x509.py                             |  4 +++-
 ipaserver/install/cainstance.py            |  2 +-
 ipaserver/install/httpinstance.py          |  2 +-
 ipaserver/install/installutils.py          |  6 +++++-
 ipaserver/install/krbinstance.py           |  2 +-
 ipaserver/install/server/replicainstall.py |  2 +-
 8 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
index 64e3ef90d9..72858490da 100644
--- a/ipaclient/install/client.py
+++ b/ipaclient/install/client.py
@@ -1879,7 +1879,7 @@ def http_url():
 
     if ca_certs is not None:
         try:
-            x509.write_certificate_list(ca_certs, ca_file)
+            x509.write_certificate_list(ca_certs, ca_file, mode=0o644)
         except Exception as e:
             if os.path.exists(ca_file):
                 try:
@@ -2874,10 +2874,14 @@ def _install(options):
 
     x509.write_certificate_list(
         [c for c, n, t, u in ca_certs if t is not False],
-        paths.KDC_CA_BUNDLE_PEM)
+        paths.KDC_CA_BUNDLE_PEM,
+        mode=0o644
+    )
     x509.write_certificate_list(
         [c for c, n, t, u in ca_certs if t is not False],
-        paths.CA_BUNDLE_PEM)
+        paths.CA_BUNDLE_PEM,
+        mode=0o644
+    )
 
     # Add the CA certificates to the IPA NSS database
     logger.debug("Adding CA certificates to the IPA NSS database.")
diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
index a67a0eae60..ea3765fcf6 100644
--- a/ipaclient/install/ipa_certupdate.py
+++ b/ipaclient/install/ipa_certupdate.py
@@ -186,10 +186,10 @@ def update_server(certs):
     update_file(paths.CACERT_PEM, certs)
 
 
-def update_file(filename, certs, mode=0o444):
+def update_file(filename, certs, mode=0o644):
     certs = (c[0] for c in certs if c[2] is not False)
     try:
-        x509.write_certificate_list(certs, filename)
+        x509.write_certificate_list(certs, filename, mode=mode)
     except Exception as e:
         logger.error("failed to update %s: %s", filename, e)
 
diff --git a/ipalib/x509.py b/ipalib/x509.py
index 7986ddbf5f..11d390d20a 100644
--- a/ipalib/x509.py
+++ b/ipalib/x509.py
@@ -553,7 +553,7 @@ def write_certificate(cert, filename):
         raise errors.FileError(reason=str(e))
 
 
-def write_certificate_list(certs, filename):
+def write_certificate_list(certs, filename, mode=None):
     """
     Write a list of certificates to a file in PEM format.
 
@@ -563,6 +563,8 @@ def write_certificate_list(certs, filename):
 
     try:
         with open(filename, 'wb') as f:
+            if mode is not None:
+                os.fchmod(f.fileno(), mode)
             for cert in certs:
                 f.write(cert.public_bytes(Encoding.PEM))
     except (IOError, OSError) as e:
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 6f95c8254d..8d01f37924 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -848,7 +848,7 @@ def __export_ca_chain(self):
         for path in [paths.IPA_CA_CRT,
                      paths.KDC_CA_BUNDLE_PEM,
                      paths.CA_BUNDLE_PEM]:
-            x509.write_certificate_list(certlist, path)
+            x509.write_certificate_list(certlist, path, mode=0o644)
 
     def __request_ra_certificate(self):
         """
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index d91fb4c10f..3fc21fd3f9 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -432,7 +432,7 @@ def __publish_ca_cert(self):
             raise RuntimeError("HTTPD cert was issued by an unknown CA.")
         # at this time we can assume any CA cert will be valid since this is
         # only run during installation
-        x509.write_certificate_list(certlist, paths.CA_CRT)
+        x509.write_certificate_list(certlist, paths.CA_CRT, mode=0o644)
 
     def is_kdcproxy_configured(self):
         """Check if KDC proxy has already been configured in the past"""
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 53b825aac3..a50084f18d 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -1104,7 +1104,11 @@ def load_external_cert(files, ca_subject):
     cert_file.flush()
 
     ca_file = tempfile.NamedTemporaryFile()
-    x509.write_certificate_list(ca_cert_chain[1:], ca_file.name)
+    x509.write_certificate_list(
+        ca_cert_chain[1:],
+        ca_file.name,
+        mode=0o644
+    )
     ca_file.flush()
 
     return cert_file, ca_file
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 6ba05b2867..023ccef5a4 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -502,7 +502,7 @@ def _install_pkinit_ca_bundle(self):
                                           self.api.env.realm,
                                           False)
         ca_certs = [c for c, _n, t, _u in ca_certs if t is not False]
-        x509.write_certificate_list(ca_certs, paths.CACERT_PEM)
+        x509.write_certificate_list(ca_certs, paths.CACERT_PEM, mode=0o644)
 
     def issue_selfsigned_pkinit_certs(self):
         self._call_certmonger(certmonger_ca="SelfSign")
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index caf3e8a54a..3ec2d6526a 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -145,7 +145,7 @@ def install_ca_cert(ldap, base_dn, realm, cafile, destfile=paths.IPA_CA_CRT):
                 pass
         else:
             certs = [c[0] for c in certs if c[2] is not False]
-            x509.write_certificate_list(certs, destfile)
+            x509.write_certificate_list(certs, destfile, mode=0o644)
     except Exception as e:
         raise ScriptError("error copying files: " + str(e))
     return destfile

From 8b5e408f88d2ab0ca9c077219e1b6f479a972ca0 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Fri, 22 Jun 2018 12:22:06 +0200
Subject: [PATCH 2/4] Always make ipa.p11-kit world-readable

Ensure that ipa.p11-kit is always world-readable.

Fixes: https://pagure.io/freeipa/issue/7594
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaplatform/redhat/tasks.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py
index eb75557a17..237681c0f3 100644
--- a/ipaplatform/redhat/tasks.py
+++ b/ipaplatform/redhat/tasks.py
@@ -280,6 +280,7 @@ def insert_ca_certs_into_systemwide_ca_store(self, ca_certs):
 
         try:
             f = open(new_cacert_path, 'w')
+            os.fchmod(f.fileno(), 0o644)
         except IOError as e:
             logger.info("Failed to open %s: %s", new_cacert_path, e)
             return False

From 085e436b738eae641c5dac6736d7500736a463e3 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Fri, 22 Jun 2018 12:25:33 +0200
Subject: [PATCH 3/4] Make /etc/httpd/alias world readable & executable

The directory /etc/httpd/alias contains public key material. It must be
world readable and executable, so any client can read public certs.

Note: executable for a directory means, that a process is allowed to
traverse into the directory.

Fixes: https://pagure.io/freeipa/issue/7594
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaserver/install/httpinstance.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 3fc21fd3f9..0341da8beb 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -181,7 +181,8 @@ def __configure_http(self):
         session_dir = os.path.dirname(self.sub_dict['GSSAPI_SESSION_KEY'])
         if not os.path.isdir(session_dir):
             os.makedirs(session_dir)
-            os.chmod(session_dir, 0o755)
+        # Must be world-readable / executable
+        os.chmod(session_dir, 0o755)
 
         target_fname = paths.HTTPD_IPA_CONF
         http_txt = ipautil.template_file(

From 65e1ad2e3487b0d9ac63a9d3289c8e77dc8fb263 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Fri, 22 Jun 2018 12:53:19 +0200
Subject: [PATCH 4/4] Fix permission of public files in upgrader

Make CA bundles, certs, and cert directories world-accessible in
upgrader.

Fixes: https://pagure.io/freeipa/issue/7594
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaserver/install/server/upgrade.py | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index d102a47442..0fe3dd10a7 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -4,12 +4,14 @@
 
 from __future__ import print_function, absolute_import
 
+import errno
 import logging
 import re
 import os
 import shutil
 import pwd
 import fileinput
+import stat
 import sys
 import tempfile
 from contextlib import contextmanager
@@ -1700,6 +1702,34 @@ def migrate_to_authselect():
     sysupgrade.set_upgrade_state('authcfg', 'migrated_to_authselect', True)
 
 
+def fix_permissions():
+    """Fix permission of public accessible files and directories
+
+    In case IPA was installed with restricted umask, some public files and
+    directories may not be readable and accessible.
+
+    See https://pagure.io/freeipa/issue/7594
+    """
+    candidates = [
+        os.path.dirname(paths.GSSAPI_SESSION_KEY),
+        paths.CA_BUNDLE_PEM,
+        paths.KDC_CA_BUNDLE_PEM,
+        paths.IPA_CA_CRT,
+        paths.IPA_P11_KIT,
+    ]
+    for filename in candidates:
+        try:
+            s = os.stat(filename)
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+            continue
+        mode = 0o755 if stat.S_ISDIR(s.st_mode) else 0o644
+        if mode != stat.S_IMODE(s.st_mode):
+            logger.debug("Fix permission of %s to %o", filename, mode)
+            os.chmod(filename, mode)
+
+
 def upgrade_configuration():
     """
     Execute configuration upgrade of the IPA services
@@ -1724,6 +1754,7 @@ def upgrade_configuration():
         ntpd_cleanup(fqdn, fstore)
 
     check_certs()
+    fix_permissions()
 
     auto_redirect = find_autoredirect(fqdn)
     sub_dict = dict(
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/freeipa-devel@lists.fedorahosted.org/message/NRNXID6QSQQH6BFFKTRP7OGJIQD6BKI3/

Reply via email to