From 55d3bab57b83a32e8c0976902deea80236f387e7 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Thu, 12 Jun 2014 17:20:19 +0200 Subject: Get CA certs for system-wide store from cert store in ipa-client-install. All of the certificates and associated key policy are now stored in /etc/pki/ca-trust/source/ipa.p11-kit. Part of https://fedorahosted.org/freeipa/ticket/3259 Part of https://fedorahosted.org/freeipa/ticket/3520 Reviewed-By: Rob Crittenden --- ipa-client/ipa-install/ipa-client-install | 14 +++-- ipaplatform/base/paths.py | 2 +- ipaplatform/base/tasks.py | 10 +-- ipaplatform/fedora/tasks.py | 100 +++++++++++++++++++++++++----- 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index c9a1d524b..08fefc86d 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -771,7 +771,7 @@ def uninstall(options, env): 'as it can cause subsequent installation to fail.') # Remove the CA cert from the systemwide certificate store - tasks.remove_ca_cert_from_systemwide_ca_store(CACERT) + tasks.remove_ca_certs_from_systemwide_ca_store() # Remove the CA cert try: @@ -2545,9 +2545,6 @@ def install(options, env, fstore, statestore): return CLIENT_INSTALL_ERROR root_logger.info("Configured /etc/sssd/sssd.conf") - # Add the CA to the platform-dependant systemwide CA store - tasks.insert_ca_cert_into_systemwide_ca_store(CACERT) - host_principal = 'host/%s@%s' % (hostname, cli_realm) if options.on_master: # If on master assume kerberos is already configured properly. @@ -2649,6 +2646,13 @@ def install(options, env, fstore, statestore): if not remote_env['enable_ra']: disable_ra() + # Get CA certificates from the certificate store + ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm, + remote_env['enable_ra']) + + # Add the CA to the platform-dependant systemwide CA store + tasks.insert_ca_certs_into_systemwide_ca_store(ca_certs) + # Add the CA to the default NSS database and trust it if not purge_ipa_certs(): root_logger.info( @@ -2662,8 +2666,6 @@ def install(options, env, fstore, statestore): root_logger.error("Failed to open /etc/pki/nssdb/ipa.txt: %s", e) return CLIENT_INSTALL_ERROR - ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm, - remote_env['enable_ra']) for cert, nickname, trusted, ext_key_usage in ca_certs: try: root_logger.debug("Attempting to add CA directly to the " diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index e32a4475f..2ab06e27a 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -80,7 +80,7 @@ class BasePathNamespace(object): PAM_LDAP_CONF = "/etc/pam_ldap.conf" PASSWD = "/etc/passwd" ETC_PKI_CA_DIR = "/etc/pki-ca" - SYSTEMWIDE_CA_STORE = "/etc/pki/ca-trust/source/anchors/" + IPA_P11_KIT = "/etc/pki/ca-trust/source/ipa.p11-kit" NSS_DB_DIR = "/etc/pki/nssdb" NSSDB_CERT8_DB = "/etc/pki/nssdb/cert8.db" NSSDB_KEY3_DB = "/etc/pki/nssdb/key3.db" diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py index 67c20f31d..a4ef0ded0 100644 --- a/ipaplatform/base/tasks.py +++ b/ipaplatform/base/tasks.py @@ -49,9 +49,9 @@ class BaseTaskNamespace(object): return - def insert_ca_cert_into_systemwide_ca_store(self, path): + def insert_ca_certs_into_systemwide_ca_store(self, ca_certs): """ - Adds the CA certificate located at 'path' to the systemwide CA store + Adds CA certificates from 'ca_certs' to the systemwide CA store (if available on the platform). Returns True if the operation succeeded, False otherwise. @@ -59,10 +59,10 @@ class BaseTaskNamespace(object): return True - def remove_ca_cert_from_systemwide_ca_store(self, path): + def remove_ca_certs_from_systemwide_ca_store(self): """ - Removes the CA certificate located at 'path' from the systemwide CA - store (if available on the platform). + Removes IPA CA certificates from the systemwide CA store + (if available on the platform). Returns True if the operation succeeded, False otherwise. """ diff --git a/ipaplatform/fedora/tasks.py b/ipaplatform/fedora/tasks.py index e7583f7bd..926c0ea66 100644 --- a/ipaplatform/fedora/tasks.py +++ b/ipaplatform/fedora/tasks.py @@ -28,12 +28,18 @@ import shutil import stat import socket import sys +import urllib +import base64 from subprocess import CalledProcessError +from nss.error import NSPRError +from pyasn1.error import PyAsn1Error from ipapython.ipa_log_manager import root_logger from ipapython import ipautil +from ipalib import x509 # FIXME: do not import from ipalib + from ipaplatform.paths import paths from ipaplatform.fedora.authconfig import FedoraAuthConfig from ipaplatform.base.tasks import BaseTaskNamespace @@ -148,19 +154,88 @@ class FedoraTaskNamespace(BaseTaskNamespace): auth_config.add_option("nostart") auth_config.execute() - def insert_ca_cert_into_systemwide_ca_store(self, cacert_path): - # Add the 'ipa-' prefix to cert name to avoid name collisions - cacert_name = os.path.basename(cacert_path) - new_cacert_path = os.path.join(paths.SYSTEMWIDE_CA_STORE, - 'ipa-%s' % cacert_name) + def insert_ca_certs_into_systemwide_ca_store(self, ca_certs): + new_cacert_path = paths.IPA_P11_KIT + + try: + f = open(new_cacert_path, 'w') + except IOError, e: + root_logger.info("Failed to open %s: %s" % (new_cacert_path, e)) + return False + + f.write("# This file was created by IPA. Do not edit.\n" + "\n") + + has_eku = set() + for cert, nickname, trusted, ext_key_usage in ca_certs: + try: + subject = x509.get_der_subject(cert, x509.DER) + issuer = x509.get_der_issuer(cert, x509.DER) + serial_number = x509.get_der_serial_number(cert, x509.DER) + public_key_info = x509.get_der_public_key_info(cert, x509.DER) + except (NSPRError, PyAsn1Error), e: + root_logger.warning( + "Failed to decode certificate \"%s\": %s", nickname, e) + continue + + label = urllib.quote(nickname) + subject = urllib.quote(subject) + issuer = urllib.quote(issuer) + serial_number = urllib.quote(serial_number) + public_key_info = urllib.quote(public_key_info) + + cert = base64.b64encode(cert) + cert = x509.make_pem(cert) + + obj = ("[p11-kit-object-v1]\n" + "class: certificate\n" + "certificate-type: x-509\n" + "certificate-category: authority\n" + "label: \"%(label)s\"\n" + "subject: \"%(subject)s\"\n" + "issuer: \"%(issuer)s\"\n" + "serial-number: \"%(serial_number)s\"\n" + "x-public-key-info: \"%(public_key_info)s\"\n" % + dict(label=label, + subject=subject, + issuer=issuer, + serial_number=serial_number, + public_key_info=public_key_info)) + if trusted is True: + obj += "trusted: true\n" + elif trusted is False: + obj += "x-distrusted: true\n" + obj += "%s\n\n" % cert + f.write(obj) + + if ext_key_usage is not None and public_key_info not in has_eku: + if not ext_key_usage: + ext_key_usage = {x509.EKU_PLACEHOLDER} + try: + ext_key_usage = x509.encode_ext_key_usage(ext_key_usage) + except PyAsn1Error, e: + root_logger.warning( + "Failed to encode extended key usage for \"%s\": %s", + nickname, e) + continue + value = urllib.quote(ext_key_usage) + obj = ("[p11-kit-object-v1]\n" + "class: x-certificate-extension\n" + "label: \"ExtendedKeyUsage for %(label)s\"\n" + "x-public-key-info: \"%(public_key_info)s\"\n" + "object-id: 2.5.29.37\n" + "value: \"%(value)s\"\n\n" % + dict(label=label, + public_key_info=public_key_info, + value=value)) + f.write(obj) + has_eku.add(public_key_info) + + f.close() # Add the CA to the systemwide CA trust database try: - shutil.copy(cacert_path, new_cacert_path) ipautil.run([paths.UPDATE_CA_TRUST]) - except OSError, e: - root_logger.info("Failed to copy %s to %s" % (cacert_path, - new_cacert_path)) except CalledProcessError, e: root_logger.info("Failed to add CA to the systemwide " "CA trust database: %s" % str(e)) @@ -171,11 +246,8 @@ class FedoraTaskNamespace(BaseTaskNamespace): return False - def remove_ca_cert_from_systemwide_ca_store(self, cacert_path): - # Derive the certificate name in the store - cacert_name = os.path.basename(cacert_path) - new_cacert_path = os.path.join(paths.SYSTEMWIDE_CA_STORE, - 'ipa-%s' % cacert_name) + def remove_ca_certs_from_systemwide_ca_store(self): + new_cacert_path = paths.IPA_P11_KIT # Remove CA cert from systemwide store if os.path.exists(new_cacert_path): -- cgit