URL: https://github.com/freeipa/freeipa/pull/4102 Author: yrro Title: #4102: [WIP] Debian: write out only one CA certificate per file Action: opened
PR body: """ ca-certificates populates /etc/ssl/certs with symlinks to its input files and then runs 'openssl rehash' to create the symlinks that libssl uses to look up a CA certificate to see if it is trused. 'openssl rehash' ignores any files that contain more than one certificate: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=945274>. With this change, we write out trusted CA certificates to /usr/local/share/ipa-ca, one certificate per file. Fixes: https://pagure.io/freeipa/issue/8106 """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/4102/head:pr4102 git checkout pr4102
From 08117a7bcf0eb893d44f8dc3f2494cb710628676 Mon Sep 17 00:00:00 2001 From: Sam Morris <[email protected]> Date: Tue, 17 Dec 2019 18:41:35 +0000 Subject: [PATCH] [WIP] Debian: write out only one CA certificate per file ca-certificates populates /etc/ssl/certs with symlinks to its input files and then runs 'openssl rehash' to create the symlinks that libssl uses to look up a CA certificate to see if it is trused. 'openssl rehash' ignores any files that contain more than one certificate: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=945274>. With this change, we write out trusted CA certificates to /usr/local/share/ipa-ca, one certificate per file. Fixes: https://pagure.io/freeipa/issue/8106 --- ipaplatform/debian/paths.py | 3 +- ipaplatform/debian/tasks.py | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/ipaplatform/debian/paths.py b/ipaplatform/debian/paths.py index 764b5a2815..d535adfe56 100644 --- a/ipaplatform/debian/paths.py +++ b/ipaplatform/debian/paths.py @@ -43,7 +43,8 @@ class DebianPathNamespace(BasePathNamespace): CHRONY_CONF = "/etc/chrony/chrony.conf" OPENLDAP_LDAP_CONF = "/etc/ldap/ldap.conf" ETC_DEBIAN_VERSION = "/etc/debian_version" - IPA_P11_KIT = "/usr/local/share/ca-certificates/ipa-ca.crt" + CA_CERTIFICATES_BUNDLE_PEM = "/usr/local/share/ca-certificates/ipa-ca.crt" + CA_CERTIFICATES_DIR = "/usr/local/share/ca-certificates/ipa-ca" # XXX could use /usr/share/ca-certificates/ipa-ca ETC_SYSCONFIG_DIR = "/etc/default" SYSCONFIG_AUTOFS = "/etc/default/autofs" SYSCONFIG_DIRSRV = "/etc/default/dirsrv" diff --git a/ipaplatform/debian/tasks.py b/ipaplatform/debian/tasks.py index 31982a0ee9..09a5d7483b 100644 --- a/ipaplatform/debian/tasks.py +++ b/ipaplatform/debian/tasks.py @@ -8,6 +8,11 @@ from __future__ import absolute_import +import errno +import logging +import os +from pathlib import Path + from ipaplatform.base.tasks import BaseTaskNamespace from ipaplatform.redhat.tasks import RedHatTaskNamespace from ipaplatform.paths import paths @@ -15,6 +20,9 @@ from ipapython import directivesetter from ipapython import ipautil +logger = logging.getLogger(__name__) + + class DebianTaskNamespace(RedHatTaskNamespace): @staticmethod def restore_pre_ipa_client_configuration(fstore, statestore, @@ -88,4 +96,92 @@ def configure_pkcs11_modules(self, fstore): def restore_pkcs11_modules(self, fstore): pass + def insert_ca_certs_into_systemwide_ca_store(self, ca_certs): + result = True + + # pylint: disable=ipa-forbidden-import + from ipalib import x509 # FixMe: break import cycle + # pylint: enable=ipa-forbidden-import + + # TODO: it would be nice to have paths.IPA_P11_KIT created here, so + # that it could still be used by p11-kit in the future if Debian were + # to adopt Red Hat's CA certificate management code. If we were to do + # that, the code should be split out into a separate method that both + # DebianTaskNamespace and RedHatTaskNamespace can call. + + ca_certificates_dir_path = Path(paths.CA_CERTIFICATES_DIR) + try: + ca_certificates_dir_path.mkdir(mode=0o755, exist_ok=True) + except OSError as e: + logger.error( + 'Could not create %s: %s', ca_certificates_dir_path, e) + return False + + for i, (cert, nickname, trusted, _ext_key_usage) in enumerate(ca_certs): + if not trusted: + continue + + try: + subject = cert.subject.rfc4514_string() + issuer = cert.issuer.rfc4514_string() + serial_number = cert.serial_number + except (PyAsn1Error, ValueError, CertificateError) as e: + logger.warning( + "Failed to decode certificate \"%s\": %s", nickname, e) + continue + + ca_path = ca_certificates_dir_path/f'ipa-ca-{i}.crt' + + try: + with open(ca_path, 'w') as f: + os.fchmod(f.fileno(), 0o644) + + f.write(f'''\ +This file was created by IPA. Do not edit. + +Subject: {subject} +Issuer: {issuer} +Serial Number (dec): {serial_number} +Serial Number (hex): {serial_number:#x} +''') + + f.write(cert.public_bytes(x509.Encoding.PEM).decode('ascii')) + except IOError as e: + logger.info("Failed to open/write to %s: %s", ca_path, e) + return False + + if not self.reload_systemwide_ca_store(): + result = False + + return result + + def remove_ca_certs_from_systemwide_ca_store(self): + result = True + update = False + + # Old versions of freeipa wrote all trusted certificates to a single + # file, which is not supported by ca-certificates. + old_cacert_paths = [paths.CA_CERTIFICATES_BUNDLE_PEM, paths.IPA_P11_KIT] + + ca_certificates_dir_path = Path(paths.CA_CERTIFICATES_DIR) + if ca_certificates_dir_path.is_dir(): + old_cacert_paths.extend(p for p in ca_certificates_dir_path.iterdir() if p.suffix == '.crt' and p.is_file()) + + for old_cacert_path in old_cacert_paths: + try: + os.remove(old_cacert_path) + except OSError as e: + if e.errno != 2: + logger.error( + "Could not remove %s: %s", old_cacert_path, e) + result = False + else: + update = True + + if update: + if not self.reload_systemwide_ca_store(): + return False + + return result + tasks = DebianTaskNamespace()
_______________________________________________ FreeIPA-devel mailing list -- [email protected] To unsubscribe send an email to [email protected] Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/[email protected]
