From 6ad8c464a43260f8f58dc262f841c35be35b57b5 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Tue, 5 Aug 2014 09:06:39 +0200 Subject: Make CA-less ipa-server-install option --root-ca-file optional. The CA cert specified by --root-ca-file option must always be the CA cert of the CA which issued the server certificates in the PKCS#12 files. As the cert is not actually user selectable, use CA cert from the PKCS#12 files by default if it is present. Document --root-ca-file in ipa-server-install man page. https://fedorahosted.org/freeipa/ticket/4457 Reviewed-By: Petr Viktorin --- ipaserver/install/dsinstance.py | 15 +++++----- ipaserver/install/installutils.py | 46 ++++++++++++++++------------- ipaserver/install/ipa_replica_prepare.py | 14 +++++++-- ipaserver/install/ipa_server_certinstall.py | 3 +- 4 files changed, 45 insertions(+), 33 deletions(-) (limited to 'ipaserver') diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 1719df46d..cc1d32709 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -223,14 +223,14 @@ info: IPA V2.0 class DsInstance(service.Service): def __init__(self, realm_name=None, domain_name=None, dm_password=None, - fstore=None, cert_nickname='Server-Cert'): + fstore=None): service.Service.__init__(self, "dirsrv", service_desc="directory server", dm_password=dm_password, ldapi=False, autobind=service.DISABLED ) - self.nickname = cert_nickname + self.nickname = 'Server-Cert' self.dm_password = dm_password self.realm = realm_name self.sub_dict = None @@ -641,24 +641,23 @@ class DsInstance(service.Service): raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0]) # We only handle one server cert - nickname = server_certs[0][0] - self.dercert = dsdb.get_cert_from_db(nickname, pem=False) + self.nickname = server_certs[0][0] + self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False) else: - nickname = self.nickname cadb = certs.CertDB(self.realm, host_name=self.fqdn, subject_base=self.subject_base) # FIXME, need to set this nickname in the RA plugin cadb.export_ca_cert('ipaCert', False) dsdb.create_from_cacert(cadb.cacert_fname, passwd=None) self.dercert = dsdb.create_server_cert( - nickname, self.fqdn, cadb) + self.nickname, self.fqdn, cadb) dsdb.create_pin_file() self.cacert_name = dsdb.cacert_name if self.ca_is_configured: dsdb.track_server_cert( - nickname, self.principal, dsdb.passwd_fname, + self.nickname, self.principal, dsdb.passwd_fname, 'restart_dirsrv %s' % self.serverid) conn = ipaldap.IPAdmin(self.fqdn) @@ -679,7 +678,7 @@ class DsInstance(service.Service): DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')), objectclass=["top", "nsEncryptionModule"], cn=["RSA"], - nsSSLPersonalitySSL=[nickname], + nsSSLPersonalitySSL=[self.nickname], nsSSLToken=["internal (software)"], nsSSLActivation=["on"], ) diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 3b9138fef..e4cf5040f 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -800,8 +800,6 @@ def check_pkcs12(pkcs12_info, ca_file, hostname): This is used for files given to --*_pkcs12 to ipa-server-install and ipa-replica-prepare. - - Return a (server cert name, CA cert names) tuple """ pkcs12_filename, pkcs12_passwd = pkcs12_info root_logger.debug('Checking PKCS#12 certificate %s', pkcs12_filename) @@ -812,13 +810,18 @@ def check_pkcs12(pkcs12_info, ca_file, hostname): # Import the CA cert first so it has a known nickname # (if it's present in the PKCS#12 it won't be overwritten) ca_cert_name = 'The Root CA' - try: - nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file) - except (ValueError, RuntimeError) as e: - raise ScriptError(str(e)) + if ca_file: + try: + nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file) + except (ValueError, RuntimeError) as e: + raise ScriptError(str(e)) # Import everything in the PKCS#12 - nssdb.import_pkcs12(pkcs12_filename, db_pwd_file.name, pkcs12_passwd) + try: + nssdb.import_pkcs12( + pkcs12_filename, db_pwd_file.name, pkcs12_passwd) + except RuntimeError as e: + raise ScriptError(str(e)) # Check we have exactly one server cert (one with a private key) server_certs = nssdb.find_server_certs() @@ -833,21 +836,23 @@ def check_pkcs12(pkcs12_info, ca_file, hostname): # Check we have the whole cert chain & the CA is in it trust_chain = nssdb.get_trust_chain(server_cert_name) - while trust_chain: - if trust_chain[0] == ca_cert_name: - break - trust_chain = trust_chain[1:] - else: - raise ScriptError( - '%s is not signed by %s, or the full certificate chain is not ' - 'present in the PKCS#12 file' % (pkcs12_filename, ca_file)) - if len(trust_chain) != 2: + if len(trust_chain) < 2: + if ca_file: + raise ScriptError( + '%s is not signed by %s, or the full certificate chain is ' + 'not present in the PKCS#12 file' % + (pkcs12_filename, ca_file)) + else: + raise ScriptError( + 'The full certificate chain is not present in %s' % + pkcs12_filename) + if ca_file and trust_chain[-2] != ca_cert_name: raise ScriptError( - 'trust chain of the server certificate in %s contains %s ' - 'certificates, expected 2' % - (pkcs12_filename, len(trust_chain))) + '%s is not signed by %s' % (pkcs12_filename, ca_file)) + ca_cert_name = trust_chain[-2] # Check server validity + nssdb.trust_root_cert(ca_cert_name) try: nssdb.verify_server_cert_validity(server_cert_name, hostname) except ValueError as e: @@ -855,8 +860,7 @@ def check_pkcs12(pkcs12_info, ca_file, hostname): 'The server certificate in %s is not valid: %s' % (pkcs12_filename, e)) - return server_cert_name - + return nssdb.get_cert(ca_cert_name) @contextmanager def private_ccache(path=None): diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py index 1099046dd..c8a978dfa 100644 --- a/ipaserver/install/ipa_replica_prepare.py +++ b/ipaserver/install/ipa_replica_prepare.py @@ -139,7 +139,7 @@ class ReplicaPrepare(admintool.AdminTool): "could not find directory instance: %s" % config_dir) def check_pkcs12(self, pkcs12_file, pkcs12_pin): - installutils.check_pkcs12( + return installutils.check_pkcs12( pkcs12_info=(pkcs12_file, pkcs12_pin), ca_file=CACERT, hostname=self.replica_fqdn) @@ -221,7 +221,8 @@ class ReplicaPrepare(admintool.AdminTool): if options.http_pin is None: raise admintool.ScriptError( "%s unlock password required" % options.http_pkcs12) - self.check_pkcs12(options.http_pkcs12, options.http_pin) + http_ca_cert = self.check_pkcs12( + options.http_pkcs12, options.http_pin) if options.dirsrv_pkcs12: if options.dirsrv_pin is None: @@ -231,7 +232,8 @@ class ReplicaPrepare(admintool.AdminTool): if options.dirsrv_pin is None: raise admintool.ScriptError( "%s unlock password required" % options.dirsrv_pkcs12) - self.check_pkcs12(options.dirsrv_pkcs12, options.dirsrv_pin) + dirsrv_ca_cert = self.check_pkcs12( + options.dirsrv_pkcs12, options.dirsrv_pin) if options.pkinit_pkcs12: if options.pkinit_pin is None: @@ -242,6 +244,12 @@ class ReplicaPrepare(admintool.AdminTool): raise admintool.ScriptError( "%s unlock password required" % options.pkinit_pkcs12) + if (options.http_pkcs12 and options.dirsrv_pkcs12 and + http_ca_cert != dirsrv_ca_cert): + raise admintool.ScriptError( + "%s and %s are not signed by the same CA certificate" % + (options.http_pkcs12, options.dirsrv_pkcs12)) + if (not ipautil.file_exists( dogtag.configured_constants().CS_CFG_PATH) and options.dirsrv_pin is None): diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py index af5d21a2a..6300a14ae 100644 --- a/ipaserver/install/ipa_server_certinstall.py +++ b/ipaserver/install/ipa_server_certinstall.py @@ -154,7 +154,7 @@ class ServerCertInstall(admintool.AdminTool): os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid) def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): - server_cert = installutils.check_pkcs12( + installutils.check_pkcs12( pkcs12_info=(self.pkcs12_fname, pkcs12_passwd), ca_file=CACERT, hostname=api.env.host) @@ -166,6 +166,7 @@ class ServerCertInstall(admintool.AdminTool): cdb.delete_cert(old_cert) cdb.import_pkcs12(self.pkcs12_fname, pkcs12_passwd) + server_cert = cdb.find_server_certs()[0][0] if api.env.enable_ra: cdb.track_server_cert(server_cert, principal, cdb.passwd_fname, -- cgit