class CertDB(object): def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None): self.secdir = nssdir self.realm = realm self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.pwd_conf = "/etc/httpd/conf/password.conf" self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError, e: raise RuntimeError( "Unable to determine the current directory: %s" % str(e)) self.self_signed_ca = ipa_self_signed() if not subject_base: self.subject_base = DN(('O', 'IPA')) if self.self_signed_ca: self.cacert_name = get_ca_nickname(self.realm, 'CN=%s Certificate Authority') else: self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024" # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
def replace_key_cert_files( self, cert, key, cert_fname, key_fname, ca_cert, passwd_fname=None, profile=None, cmgr_post_command=None ): try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: certmonger.stop_tracking(certfile=cert_fname) pkey_passwd = None if passwd_fname is not None: with open(passwd_fname, 'rb') as f: pkey_passwd = f.read() x509.write_certificate(cert, cert_fname) x509.write_pem_private_key(key, key_fname, pkey_passwd) if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA cdb = certs.CertDB(api.env.realm, nssdir=paths.IPA_NSSDB_DIR) ipa_ca_cert = cdb.get_cert_from_db( get_ca_nickname(api.env.realm)) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: req_id = certmonger.start_tracking( (cert_fname, key_fname), pinfile=passwd_fname, storage='FILE', post_command=cmgr_post_command ) return req_id except RuntimeError as e: raise admintool.ScriptError(str(e)) return None
def test_cacert_manage(self): """Exercise ipa-cacert-manage delete""" # deletion without nickname result = self.master.run_command( ['ipa-cacert-manage', 'delete'], raiseonerr=False ) assert result.returncode != 0 # deletion with an unknown nickname result = self.master.run_command( ['ipa-cacert-manage', 'delete', 'unknown'], raiseonerr=False ) assert result.returncode != 0 assert "Unknown CA 'unknown'" in result.stderr_text # deletion of IPA CA ipa_ca_nickname = get_ca_nickname(self.master.domain.realm) result = self.master.run_command( ['ipa-cacert-manage', 'delete', ipa_ca_nickname], raiseonerr=False ) assert result.returncode != 0 assert 'The IPA CA cannot be removed with this tool' in \ result.stderr_text # Install 3rd party CA's, Let's Encrypt in this case for cert in (isrgrootx1, letsencryptauthorityx3): certfile = os.path.join(self.master.config.test_dir, 'cert.pem') self.master.put_file_contents(certfile, cert) result = self.master.run_command( ['ipa-cacert-manage', 'install', certfile], ) # deletion of a root CA needed by a subCA, without -f option result = self.master.run_command( ['ipa-cacert-manage', 'delete', isrgrootx1_nick], raiseonerr=False ) assert result.returncode != 0 assert "Verifying \'%s\' failed. Removing part of the " \ "chain? certutil: certificate is invalid: Peer's " \ "Certificate issuer is not recognized." \ % isrgrootx1_nick in result.stderr_text # deletion of a root CA needed by a subCA, with -f option result = self.master.run_command( ['ipa-cacert-manage', 'delete', isrgrootx1_nick, '-f'], raiseonerr=False ) assert result.returncode == 0 # deletion of a subca result = self.master.run_command( ['ipa-cacert-manage', 'delete', le_x3_nick], raiseonerr=False ) assert result.returncode == 0
def replace_key_cert_files( self, cert, key, cert_fname, key_fname, ca_cert, profile=None, cmgr_post_command=None ): try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: certmonger.stop_tracking(certfile=cert_fname) x509.write_certificate(cert, cert_fname) x509.write_pem_private_key(key, key_fname) if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA cdb = certs.CertDB(api.env.realm, nssdir=paths.IPA_NSSDB_DIR) ipa_ca_cert = cdb.get_cert_from_db( get_ca_nickname(api.env.realm)) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: req_id = certmonger.start_tracking( (cert_fname, key_fname), storage='FILE', post_command=cmgr_post_command ) return req_id except RuntimeError as e: raise admintool.ScriptError(str(e))
def load_cacert(self, cacert_fname): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close() ca_dn = DN(('CN','Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) (rdn, subject_dn) = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.run_certutil(["-A", "-n", nick, "-t", "CT,,C", "-a"], stdin=cert) except RuntimeError: break
class CertDB(object): """An IPA-server-specific wrapper around NSS This class knows IPA-specific details such as nssdir location, or the CA cert name. """ # TODO: Remove all selfsign code def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None): self.nssdb = NSSDatabase(nssdir) self.secdir = nssdir self.realm = realm self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.pwd_conf = paths.HTTPD_PASSWORD_CONF self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError, e: raise RuntimeError( "Unable to determine the current directory: %s" % str(e)) if not subject_base: self.subject_base = DN(('O', 'IPA')) self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024" # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
def delete(self): options = self.options nickname = self.args[1] conn = api.Backend.ldap2 ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2, api.env.basedn, api.env.realm, False) ipa_ca_nickname = get_ca_nickname(api.env.realm) found = False for _ca_cert, ca_nickname, _ca_trust_flags in ca_certs: if ca_nickname == nickname: if ca_nickname == ipa_ca_nickname: raise admintool.ScriptError( 'The IPA CA cannot be removed with this tool') else: found = True break if not found: raise admintool.ScriptError('Unknown CA \'{}\''.format(nickname)) with certs.NSSDatabase() as tmpdb: tmpdb.create_db() for ca_cert, ca_nickname, ca_trust_flags in ca_certs: tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags) loaded = tmpdb.list_certs() logger.debug("loaded raw certs '%s'", loaded) tmpdb.delete_cert(nickname) for ca_nickname, _trust_flags in loaded: if ca_nickname == nickname: continue elif ipa_ca_nickname == nickname: raise admintool.ScriptError("The IPA CA cannot be removed") logger.debug("Verifying %s", ca_nickname) try: tmpdb.verify_ca_cert_validity(ca_nickname) except ValueError as e: msg = "Verifying \'%s\' failed. Removing part of the " \ "chain? %s" % (nickname, e) if options.force: print(msg) continue raise admintool.ScriptError(msg) else: logger.debug("Verified %s", ca_nickname) for _ca_cert, ca_nickname, _ca_trust_flags in ca_certs: if ca_nickname == nickname: container_dn = DN(('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) dn = DN(('cn', nickname), container_dn) logger.debug("Deleting %s", ca_nickname) conn.delete_entry(dn) return
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) self.nssdb.run_pk12util([ "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname ])
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) ipautil.run([ paths.PK12UTIL, "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname ])
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) ipautil.run([ "/usr/bin/pk12util", "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname ])
def __init__(self, realm, nssdir, fstore=None, host_name=None, subject_base=None, ca_subject=None, user=None, group=None, mode=None, create=False): self.nssdb = NSSDatabase(nssdir) self.secdir = nssdir self.realm = realm self.noise_fname = self.secdir + "/noise.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.ca_subject = ca_subject self.subject_base = subject_base try: self.cwd = os.path.abspath(os.getcwd()) except OSError as e: raise RuntimeError( "Unable to determine the current directory: %s" % str(e)) self.cacert_name = get_ca_nickname(self.realm) self.user = user self.group = group self.mode = mode self.uid = 0 self.gid = 0 if not create: if os.path.isdir(self.secdir): # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] else: if user is not None: pu = pwd.getpwnam(user) self.uid = pu.pw_uid self.gid = pu.pw_gid if group is not None: self.gid = grp.getgrnam(group).gr_gid self.create_certdbs() if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
def __init__(self, realm, nssdir, fstore=None, host_name=None, subject_base=None, ca_subject=None, user=None, group=None, mode=None, create=False, dbtype='auto'): self.nssdb = NSSDatabase(nssdir, dbtype=dbtype) self.realm = realm self.noise_fname = os.path.join(self.secdir, "noise.txt") self.pk12_fname = os.path.join(self.secdir, "cacert.p12") self.pin_fname = os.path.join(self.secdir + "pin.txt") self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.ca_subject = ca_subject self.subject_base = subject_base self.cacert_name = get_ca_nickname(self.realm) self.user = user self.group = group self.mode = mode self.uid = 0 self.gid = 0 if not create: if os.path.isdir(self.secdir): # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] else: if user is not None: pu = pwd.getpwnam(user) self.uid = pu.pw_uid self.gid = pu.pw_gid if group is not None: self.gid = grp.getgrnam(group).gr_gid self.create_certdbs() if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) ipautil.run([paths.PK12UTIL, "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname])
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname])
def install_kdc_cert(self): ca_cert_file = paths.CA_BUNDLE_PEM pkcs12_file, pin, ca_cert = installutils.load_pkcs12( cert_files=self.args, key_password=self.options.pin, key_nickname=self.options.cert_name, ca_cert_files=[ca_cert_file], realm_name=api.env.realm) cdb = certs.CertDB(api.env.realm, nssdir=paths.IPA_NSSDB_DIR) # Check that the ca_cert is known and trusted with tempfile.NamedTemporaryFile() as temp: certs.install_pem_from_p12(pkcs12_file.name, pin, temp.name) kdc_cert = x509.load_certificate_from_file(temp.name) ca_certs = x509.load_certificate_list_from_file(ca_cert_file) try: verify_kdc_cert_validity(kdc_cert, ca_certs, api.env.realm) except ValueError as e: raise admintool.ScriptError( "Peer's certificate issuer is not trusted (%s). " "Please run ipa-cacert-manage install and ipa-certupdate " "to install the CA certificate." % str(e)) try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: certmonger.stop_tracking(certfile=paths.KDC_CERT) certs.install_pem_from_p12(pkcs12_file.name, pin, paths.KDC_CERT) certs.install_key_from_p12(pkcs12_file.name, pin, paths.KDC_KEY) if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA ipa_ca_cert = cdb.get_cert_from_db( get_ca_nickname(api.env.realm), pem=False) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: certmonger.start_tracking( (paths.KDC_CERT, paths.KDC_KEY), storage='FILE', profile='KDCs_PKINIT_Certs') except RuntimeError as e: raise admintool.ScriptError(str(e)) krb = krbinstance.KrbInstance() krb.init_info( realm_name=api.env.realm, host_name=api.env.host, ) krb.pkinit_enable()
def install_kdc_cert(self): ca_cert_file = paths.CA_BUNDLE_PEM pkcs12_file, pin, ca_cert = installutils.load_pkcs12( cert_files=self.args, key_password=self.options.pin, key_nickname=self.options.cert_name, ca_cert_files=[ca_cert_file], realm_name=api.env.realm) cdb = certs.CertDB(api.env.realm, nssdir=paths.IPA_NSSDB_DIR) # Check that the ca_cert is known and trusted with tempfile.NamedTemporaryFile() as temp: certs.install_pem_from_p12(pkcs12_file.name, pin, temp.name) kdc_cert = x509.load_certificate_from_file(temp.name) ca_certs = x509.load_certificate_list_from_file(ca_cert_file) try: verify_kdc_cert_validity(kdc_cert, ca_certs, api.env.realm) except ValueError as e: raise admintool.ScriptError( "Peer's certificate issuer is not trusted (%s). " "Please run ipa-cacert-manage install and ipa-certupdate " "to install the CA certificate." % str(e)) try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: certmonger.stop_tracking(certfile=paths.KDC_CERT) certs.install_pem_from_p12(pkcs12_file.name, pin, paths.KDC_CERT) certs.install_key_from_p12(pkcs12_file.name, pin, paths.KDC_KEY) if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA ipa_ca_cert = cdb.get_cert_from_db(get_ca_nickname( api.env.realm), pem=False) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: certmonger.start_tracking((paths.KDC_CERT, paths.KDC_KEY), storage='FILE', profile='KDCs_PKINIT_Certs') except RuntimeError as e: raise admintool.ScriptError(str(e)) krb = krbinstance.KrbInstance() krb.init_info( realm_name=api.env.realm, host_name=api.env.host, ) krb.pkinit_enable()
def execute(self, **options): db = certs.CertDB(self.api.env.realm) ca_cert = None ca_enabled = self.api.Command.ca_is_enabled()['result'] if ca_enabled: ca_nickname = certdb.get_ca_nickname(self.api.env.realm) else: ca_nickname = None server_certs = db.find_server_certs() if server_certs: ca_chain = db.find_root_cert(server_certs[0][0])[:-1] if ca_chain: ca_nickname = ca_chain[-1] ldap = self.api.Backend.ldap2 for nickname, trust_flags in db.list_certs(): if 'u' in trust_flags: continue if nickname == ca_nickname and ca_enabled: trust_flags = 'CT,C,C' cert = db.get_cert_from_db(nickname, pem=False) trust, ca, eku = certstore.trust_flags_to_key_policy(trust_flags) dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), ('cn','etc'), self.api.env.basedn) entry = ldap.make_entry(dn) try: certstore.init_ca_entry(entry, cert, nickname, trust, eku) except Exception, e: self.log.warning("Failed to create entry for %s: %s", nickname, e) continue if nickname == ca_nickname: ca_cert = cert config = entry.setdefault('ipaConfigString', []) if ca_enabled: config.append('ipaCa') config.append('ipaCa') try: ldap.add_entry(entry) except errors.DuplicateEntry: pass
def execute(self, **options): # If CA is disabled, no need to check for duplicates of IPA CA ca_enabled = self.api.Command.ca_is_enabled()['result'] if not ca_enabled: return False, [] # Look for the IPA CA cert subject ldap = self.api.Backend.ldap2 cacert_subject = certstore.get_ca_subject(ldap, self.api.env.container_ca, self.api.env.basedn) cacert_nick = get_ca_nickname(self.api.env.realm) # Find if there are other certificates with the same subject # They are duplicates resulting of BZ 1480102 base_dn = DN(('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) filter = ldap.combine_filters( [ # all certificates with CA cert subject ldap.make_filter({'ipaCertSubject': cacert_subject}), # except the default certificate ldap.make_filter({'cn': cacert_nick}, rules=ldap.MATCH_NONE), ], rules=ldap.MATCH_ALL) try: result, _truncated = ldap.find_entries(base_dn=base_dn, filter=filter, attrs_list=[]) except errors.NotFound: # No duplicate, we're good logger.debug("No duplicates for IPA CA in LDAP") return False, [] logger.debug("Found %d entrie(s) for IPA CA in LDAP", len(result)) for entry in result: # Remove the duplicate try: ldap.delete_entry(entry) logger.debug("Removed the duplicate %s", entry.dn) except Exception as e: logger.warning("Failed to remove the duplicate %s: %s", entry.dn, e) return True, []
def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None): self.nssdb = NSSDatabase(nssdir) self.secdir = nssdir self.realm = realm self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.pwd_conf = paths.HTTPD_PASSWORD_CONF self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError as e: raise RuntimeError("Unable to determine the current directory: %s" % str(e)) if not subject_base: self.subject_base = DN(('O', 'IPA')) self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024" # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): # Fetch all needed certs one by one, then combine them in a single # PKCS12 file prefix = data['prefix'] certlist = data['list'] cli = self._get_custodia_client(server=ca_host) with NSSDatabase(None) as tmpdb: tmpdb.create_db() # Cert file password crtpwfile = os.path.join(tmpdb.secdir, 'crtpwfile') with open(crtpwfile, 'w+') as f: f.write(cacerts_pwd) for nickname in certlist: value = cli.fetch_key(os.path.join(prefix, nickname), False) v = json_decode(value) pk12pwfile = os.path.join(tmpdb.secdir, 'pk12pwfile') with open(pk12pwfile, 'w+') as f: f.write(v['export password']) pk12file = os.path.join(tmpdb.secdir, 'pk12file') with open(pk12file, 'wb') as f: f.write(b64decode(v['pkcs12 data'])) tmpdb.run_pk12util([ '-k', tmpdb.pwd_file, '-n', nickname, '-i', pk12file, '-w', pk12pwfile ]) # Add CA certificates, but don't import the main CA cert. It's # already present as 'caSigningCert cert-pki-ca'. With SQL db # format, a second import would rename the certificate. See # https://pagure.io/freeipa/issue/7498 for more details. conn = api.Backend.ldap2 suffix = ipautil.realm_to_suffix(self.realm) ca_certs = get_ca_certs_nss(conn, suffix, self.realm, True) for cert, nickname, trust_flags in ca_certs: if nickname == get_ca_nickname(self.realm): continue tmpdb.add_cert(cert, nickname, trust_flags) # Now that we gathered all certs, re-export ipautil.run([ paths.PKCS12EXPORT, '-d', tmpdb.secdir, '-p', tmpdb.pwd_file, '-w', crtpwfile, '-o', cacerts_file ])
def execute(self, **options): # If CA is disabled, no need to check for duplicates of IPA CA ca_enabled = self.api.Command.ca_is_enabled()['result'] if not ca_enabled: return True, [] # Look for the IPA CA cert subject ldap = self.api.Backend.ldap2 cacert_subject = certstore.get_ca_subject( ldap, self.api.env.container_ca, self.api.env.basedn) # Find if there are other certificates with the same subject # They are duplicates resulting of BZ 1480102 base_dn = DN(('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) try: filter = ldap.make_filter({'ipaCertSubject': cacert_subject}) result, _truncated = ldap.find_entries( base_dn=base_dn, filter=filter, attrs_list=[]) except errors.NotFound: # No duplicate, we're good logger.debug("No duplicates for IPA CA in LDAP") return True, [] logger.debug("Found %d entrie(s) for IPA CA in LDAP", len(result)) cacert_dn = DN(('cn', get_ca_nickname(self.api.env.realm)), base_dn) for entry in result: if entry.dn == cacert_dn: continue # Remove the duplicate try: ldap.delete_entry(entry) logger.debug("Removed the duplicate %s", entry.dn) except Exception as e: logger.warning("Failed to remove the duplicate %s: %s", entry.dn, e) return True, []
def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): pkcs12_file, pin, ca_cert = installutils.load_pkcs12( cert_files=self.args, key_password=pkcs12_passwd, key_nickname=self.options.cert_name, ca_cert_files=[CACERT], host_name=api.env.host) dirname = os.path.normpath(dirname) cdb = certs.CertDB(api.env.realm, nssdir=dirname) # Check that the ca_cert is known and trusted self.check_chain(pkcs12_file.name, pin, cdb) try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: cdb.untrack_server_cert(old_cert) cdb.delete_cert(old_cert) prevs = cdb.find_server_certs() cdb.import_pkcs12(pkcs12_file.name, pin) news = cdb.find_server_certs() server_certs = [item for item in news if item not in prevs] server_cert = server_certs[0][0] if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA ipa_ca_cert = cdb.get_cert_from_db( get_ca_nickname(api.env.realm), pem=False) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: cdb.track_server_cert(server_cert, principal, cdb.passwd_fname, command) except RuntimeError as e: raise admintool.ScriptError(str(e)) return server_cert
def load_cacert(self, cacert_fname, trust_flags): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ with open(cacert_fname) as f: certs = f.read() st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) _rdn, subject_dn = get_cert_nickname(cert) if subject_dn == self.ca_subject: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.nssdb.add_cert(cert, nick, trust_flags, pem=True) except RuntimeError: break
def load_cacert(self, cacert_fname, trust_flags): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ with open(cacert_fname) as f: certs = f.read() st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) _rdn, subject_dn = get_cert_nickname(cert) if subject_dn == self.ca_subject: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.nssdb.add_cert(cert, nick, trust_flags) except RuntimeError: break
def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): pkcs12_file, pin, ca_cert = installutils.load_pkcs12( cert_files=self.args, key_password=pkcs12_passwd, key_nickname=self.options.cert_name, ca_cert_files=[paths.IPA_CA_CRT], host_name=api.env.host) dirname = os.path.normpath(dirname) cdb = certs.CertDB(api.env.realm, nssdir=dirname) # Check that the ca_cert is known and trusted self.check_chain(pkcs12_file.name, pin, cdb) try: ca_enabled = api.Command.ca_is_enabled()['result'] if ca_enabled: cdb.untrack_server_cert(old_cert) cdb.delete_cert(old_cert) prevs = cdb.find_server_certs() cdb.import_pkcs12(pkcs12_file.name, pin) news = cdb.find_server_certs() server_certs = [item for item in news if item not in prevs] server_cert = server_certs[0][0] if ca_enabled: # Start tracking only if the cert was issued by IPA CA # Retrieve IPA CA ipa_ca_cert = cdb.get_cert_from_db( get_ca_nickname(api.env.realm)) # And compare with the CA which signed this certificate if ca_cert == ipa_ca_cert: cdb.track_server_cert(server_cert, principal, cdb.passwd_fname, command) except RuntimeError as e: raise admintool.ScriptError(str(e)) return server_cert
def load_cacert(self, cacert_fname, trust_flags): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close() ca_dn = DN(('CN', 'Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) _rdn, subject_dn = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.nssdb.add_cert(cert, nick, trust_flags, pem=True) except RuntimeError: break
def load_cacert(self, cacert_fname, trust_flags): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close() ca_dn = DN(('CN','Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) (rdn, subject_dn) = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.nssdb.add_cert(cert, nick, trust_flags, pem=True) except RuntimeError: break
def load_cacert(self, cacert_fname): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close() ca_dn = DN(('CN', 'Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) (rdn, subject_dn) = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.run_certutil(["-A", "-n", nick, "-t", "CT,,C", "-a"], stdin=cert) except RuntimeError: break
def make_compat_ca_certs(certs, realm, ipa_ca_subject): """ Make CA certificates and associated key policy from DER certificates. """ result = [] for cert in certs: subject, _issuer_serial, _public_key_info = _parse_cert(cert) subject = DN(subject) if ipa_ca_subject is not None and subject == DN(ipa_ca_subject): nickname = get_ca_nickname(realm) ext_key_usage = { x509.EKU_SERVER_AUTH, x509.EKU_CLIENT_AUTH, x509.EKU_EMAIL_PROTECTION, x509.EKU_CODE_SIGNING } else: nickname = str(subject) ext_key_usage = {x509.EKU_SERVER_AUTH} result.append((cert, nickname, True, ext_key_usage)) return result
def make_compat_ca_certs(certs, realm, ipa_ca_subject): """ Make CA certificates and associated key policy from DER certificates. """ result = [] for cert in certs: subject, _issuer_serial, _public_key_info = _parse_cert(cert) subject = DN(subject) if ipa_ca_subject is not None and subject == DN(ipa_ca_subject): nickname = get_ca_nickname(realm) ext_key_usage = {x509.EKU_SERVER_AUTH, x509.EKU_CLIENT_AUTH, x509.EKU_EMAIL_PROTECTION, x509.EKU_CODE_SIGNING} else: nickname = str(subject) ext_key_usage = {x509.EKU_SERVER_AUTH} result.append((cert, nickname, True, ext_key_usage)) return result
def execute(self, **options): db = certs.CertDB(self.api.env.realm, paths.HTTPD_ALIAS_DIR) ca_cert = None ca_enabled = self.api.Command.ca_is_enabled()['result'] if ca_enabled: ca_nickname = certdb.get_ca_nickname(self.api.env.realm) else: ca_nickname = None server_certs = db.find_server_certs() if server_certs: ca_chain = db.find_root_cert(server_certs[0][0])[:-1] if ca_chain: ca_nickname = ca_chain[-1] ldap = self.api.Backend.ldap2 for nickname, trust_flags in db.list_certs(): if trust_flags.has_key: continue if nickname == ca_nickname and ca_enabled: trust_flags = certdb.IPA_CA_TRUST_FLAGS cert = db.get_cert_from_db(nickname, pem=False) trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags) dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) entry = ldap.make_entry(dn) try: certstore.init_ca_entry(entry, cert, nickname, trust, eku) except Exception as e: self.log.warning("Failed to create entry for %s: %s", nickname, e) continue if nickname == ca_nickname: ca_cert = cert config = entry.setdefault('ipaConfigString', []) if ca_enabled: config.append('ipaCa') config.append('ipaCa') try: ldap.add_entry(entry) except errors.DuplicateEntry: if nickname == ca_nickname and ca_enabled: try: ldap.update_entry(entry) except errors.EmptyModlist: pass if ca_cert: dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) try: entry = ldap.get_entry(dn) except errors.NotFound: entry = ldap.make_entry(dn) entry['objectclass'] = ['nsContainer', 'pkiCA'] entry.single_value['cn'] = 'CAcert' entry.single_value['cACertificate;binary'] = ca_cert ldap.add_entry(entry) else: if b'' in entry['cACertificate;binary']: entry.single_value['cACertificate;binary'] = ca_cert ldap.update_entry(entry) return False, []
def execute(self, **options): db = certs.CertDB(self.api.env.realm, paths.HTTPD_ALIAS_DIR) ca_cert = None ca_enabled = self.api.Command.ca_is_enabled()['result'] if ca_enabled: ca_nickname = certdb.get_ca_nickname(self.api.env.realm) else: ca_nickname = None server_certs = db.find_server_certs() if server_certs: ca_chain = db.find_root_cert(server_certs[0][0])[:-1] if ca_chain: ca_nickname = ca_chain[-1] ldap = self.api.Backend.ldap2 for nickname, trust_flags in db.list_certs(): if trust_flags.has_key: continue if nickname == ca_nickname and ca_enabled: trust_flags = certdb.IPA_CA_TRUST_FLAGS cert = db.get_cert_from_db(nickname, pem=False) trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags) dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), ('cn','etc'), self.api.env.basedn) entry = ldap.make_entry(dn) try: certstore.init_ca_entry(entry, cert, nickname, trust, eku) except Exception as e: self.log.warning("Failed to create entry for %s: %s", nickname, e) continue if nickname == ca_nickname: ca_cert = cert config = entry.setdefault('ipaConfigString', []) if ca_enabled: config.append('ipaCa') config.append('ipaCa') try: ldap.add_entry(entry) except errors.DuplicateEntry: if nickname == ca_nickname and ca_enabled: try: ldap.update_entry(entry) except errors.EmptyModlist: pass if ca_cert: dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn','etc'), self.api.env.basedn) try: entry = ldap.get_entry(dn) except errors.NotFound: entry = ldap.make_entry(dn) entry['objectclass'] = ['nsContainer', 'pkiCA'] entry.single_value['cn'] = 'CAcert' entry.single_value['cACertificate;binary'] = ca_cert ldap.add_entry(entry) else: if b'' in entry['cACertificate;binary']: entry.single_value['cACertificate;binary'] = ca_cert ldap.update_entry(entry) return False, []
def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file if replica_config is not None and not replica_config.setup_ca: return realm_name = options.realm_name host_name = options.host_name subject_base = options.subject if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': raise ScriptError('A selfsign CA can not be added') cafile = os.path.join(replica_config.dir, 'cacert.p12') if not options.promote and not ipautil.file_exists(cafile): raise ScriptError('CA cannot be installed in CA-less setup.') if standalone and not options.skip_conncheck: principal = options.principal replica_conn_check(replica_config.ca_host_name, host_name, realm_name, True, replica_config.ca_ds_port, options.admin_password, principal=principal, ca_cert_file=options.ca_cert_file) if options.skip_schema_check: root_logger.info("Skipping CA DS schema check") else: cainstance.replica_ca_install_check(replica_config, options.promote) return if standalone: if api.Command.ca_is_enabled()['result']: raise ScriptError( "One or more CA masters are already present in IPA realm " "'%s'.\nIf you wish to replicate CA to this host, please " "re-run 'ipa-ca-install'\nwith a replica file generated on " "an existing CA master as argument." % realm_name) if options.external_cert_files: if not cainstance.is_step_one_done(): # This can happen if someone passes external_ca_file without # already having done the first stage of the CA install. raise ScriptError( "CA is not installed yet. To install with an external CA " "is a two-stage process.\nFirst run the installer with " "--external-ca.") external_cert_file, external_ca_file = installutils.load_external_cert( options.external_cert_files, options.subject) elif options.external_ca: if cainstance.is_step_one_done(): raise ScriptError( "CA is already installed.\nRun the installer with " "--external-cert-file.") if ipautil.file_exists(paths.ROOT_IPA_CSR): raise ScriptError( "CA CSR file %s already exists.\nIn order to continue " "remove the file and run the installer again." % paths.ROOT_IPA_CSR) if not options.external_cert_files: if not cainstance.check_port(): print("IPA requires port 8443 for PKI but it is currently in use.") raise ScriptError("Aborting installation") if standalone: dirname = dsinstance.config_dirname( installutils.realm_to_serverid(realm_name)) cadb = certs.CertDB(realm_name, subject_base=subject_base) dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base) for db in (cadb, dsdb): for nickname, _trust_flags in db.list_certs(): if nickname in (certdb.get_ca_nickname(realm_name), 'ipaCert'): raise ScriptError( "Certificate with nickname %s is present in %s, " "cannot continue." % (nickname, db.secdir)) cert = db.get_cert_from_db(nickname) if not cert: continue subject = DN(x509.load_certificate(cert).subject) if subject in (DN('CN=Certificate Authority', subject_base), DN('CN=IPA RA', subject_base)): raise ScriptError( "Certificate with subject %s is present in %s, " "cannot continue." % (subject, db.secdir))
def install_step_1(standalone, replica_config, options, custodia): if replica_config is not None and not replica_config.setup_ca: return realm_name = options.realm_name host_name = options.host_name subject_base = options._subject_base basedn = ipautil.realm_to_suffix(realm_name) ca = cainstance.CAInstance(realm=realm_name, host_name=host_name, custodia=custodia) ca.stop('pki-tomcat') # This is done within stopped_service context, which restarts CA ca.enable_client_auth_to_db() # Lightweight CA key retrieval is configured in step 1 instead # of CAInstance.configure_instance (which is invoked from step # 0) because kadmin_addprinc fails until krb5.conf is installed # by krb.create_instance. # ca.setup_lightweight_ca_key_retrieval() serverid = ipaldap.realm_to_serverid(realm_name) if standalone and replica_config is None: dirname = dsinstance.config_dirname(serverid) # Store the new IPA CA cert chain in DS NSS database and LDAP cadb = certs.CertDB(realm_name, nssdir=paths.PKI_TOMCAT_ALIAS_DIR, subject_base=subject_base) dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base) cacert = cadb.get_cert_from_db('caSigningCert cert-pki-ca') nickname = certdb.get_ca_nickname(realm_name) trust_flags = certdb.IPA_CA_TRUST_FLAGS dsdb.add_cert(cacert, nickname, trust_flags) certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn, cacert, nickname, trust_flags, config_ipa=True, config_compat=True) # Store DS CA cert in Dogtag NSS database trust_flags = dict(reversed(dsdb.list_certs())) server_certs = dsdb.find_server_certs() trust_chain = dsdb.find_root_cert(server_certs[0][0])[:-1] nickname = trust_chain[-1] cert = dsdb.get_cert_from_db(nickname) cadb.add_cert(cert, nickname, trust_flags[nickname]) installutils.restart_dirsrv() ca.start('pki-tomcat') if standalone or replica_config is not None: # We need to restart apache as we drop a new config file in there services.knownservices.httpd.restart(capture_output=True) if standalone: # Install CA DNS records if bindinstance.dns_container_exists(basedn): bind = bindinstance.BindInstance() bind.update_system_records()
def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file realm_name = options.realm_name host_name = options.host_name if replica_config is None: options._subject_base = options.subject_base options._ca_subject = options.ca_subject else: # during replica install, this gets invoked before local DS is # available, so use the remote api. _api = api if standalone else options._remote_api # for replica-install the knobs cannot be written, hence leading '_' options._subject_base = str(replica_config.subject_base) options._ca_subject = lookup_ca_subject(_api, options._subject_base) if replica_config is not None and not replica_config.setup_ca: return if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': raise ScriptError('A selfsign CA can not be added') if standalone and not options.skip_conncheck: principal = options.principal replica_conn_check(replica_config.ca_host_name, host_name, realm_name, True, replica_config.ca_ds_port, options.admin_password, principal=principal, ca_cert_file=options.ca_cert_file) if options.skip_schema_check: logger.info("Skipping CA DS schema check") return if standalone: if api.Command.ca_is_enabled()['result']: raise ScriptError( "One or more CA masters are already present in IPA realm " "'%s'.\nIf you wish to replicate CA to this host, please " "re-run 'ipa-ca-install'\nwith a replica file generated on " "an existing CA master as argument." % realm_name) if options.external_cert_files: if not cainstance.is_step_one_done(): # This can happen if someone passes external_ca_file without # already having done the first stage of the CA install. raise ScriptError( "CA is not installed yet. To install with an external CA " "is a two-stage process.\nFirst run the installer with " "--external-ca.") external_cert_file, external_ca_file = installutils.load_external_cert( options.external_cert_files, options._ca_subject) elif options.external_ca: if cainstance.is_step_one_done(): raise ScriptError( "CA is already installed.\nRun the installer with " "--external-cert-file.") if os.path.isfile(paths.ROOT_IPA_CSR): raise ScriptError( "CA CSR file %s already exists.\nIn order to continue " "remove the file and run the installer again." % paths.ROOT_IPA_CSR) if not options.external_ca_type: options.external_ca_type = x509.ExternalCAType.GENERIC.value if options.external_ca_profile is not None: # check that profile is valid for the external ca type if options.external_ca_type \ not in options.external_ca_profile.valid_for: raise ScriptError( "External CA profile specification '{}' " "cannot be used with external CA type '{}'.".format( options.external_ca_profile.unparsed_input, options.external_ca_type)) if not options.external_cert_files: if not cainstance.check_ports(): print("IPA requires ports 8080 and 8443 for PKI, but one or more " "are currently in use.") raise ScriptError("Aborting installation") if standalone: dirname = dsinstance.config_dirname( ipaldap.realm_to_serverid(realm_name)) cadb = certs.CertDB(realm_name, nssdir=paths.PKI_TOMCAT_ALIAS_DIR, subject_base=options._subject_base) dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=options._subject_base) # Check that we can add our CA cert to DS and PKI NSS databases for db in (cadb, dsdb): if not db.exists(): continue for nickname, _trust_flags in db.list_certs(): if nickname == certdb.get_ca_nickname(realm_name): raise ScriptError( "Certificate with nickname %s is present in %s, " "cannot continue." % (nickname, db.secdir)) cert = db.get_cert_from_db(nickname) if not cert: continue subject = DN(cert.subject) if subject == DN(options._ca_subject): raise ScriptError( "Certificate with subject %s is present in %s, " "cannot continue." % (subject, db.secdir))
def execute(self, **options): serverid = realm_to_serverid(self.api.env.realm) db = certs.CertDB(self.api.env.realm, nssdir=dsinstance.config_dirname(serverid)) ca_cert = None ca_enabled = self.api.Command.ca_is_enabled()['result'] if ca_enabled: ca_nickname = certdb.get_ca_nickname(self.api.env.realm) ca_subject = certstore.get_ca_subject( self.api.Backend.ldap2, self.api.env.container_ca, self.api.env.basedn) else: ca_nickname = None server_certs = db.find_server_certs() if server_certs: ca_chain = db.find_root_cert(server_certs[0][0])[:-1] if ca_chain: ca_nickname = ca_chain[-1] ldap = self.api.Backend.ldap2 for nickname, trust_flags in db.list_certs(): if trust_flags.has_key: continue cert = db.get_cert_from_db(nickname) subject = cert.subject if ca_enabled and subject == ca_subject: # When ca is enabled, we can have the IPA CA cert stored # in the nss db with a different nickname (for instance # when the server was installed with --subject to # customize the CA cert subject), but it must always be # stored in LDAP with the DN cn=$DOMAIN IPA CA # This is why we check the subject instead of the nickname here nickname = ca_nickname trust_flags = certdb.IPA_CA_TRUST_FLAGS trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags) dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), ('cn','etc'), self.api.env.basedn) entry = ldap.make_entry(dn) try: certstore.init_ca_entry(entry, cert, nickname, trust, eku) except Exception as e: logger.warning("Failed to create entry for %s: %s", nickname, e) continue if nickname == ca_nickname: ca_cert = cert config = entry.setdefault('ipaConfigString', []) if ca_enabled: config.append('ipaCa') config.append('ipaCa') try: ldap.add_entry(entry) except errors.DuplicateEntry: if nickname == ca_nickname and ca_enabled: try: ldap.update_entry(entry) except errors.EmptyModlist: pass if ca_cert: dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn','etc'), self.api.env.basedn) try: entry = ldap.get_entry(dn) except errors.NotFound: entry = ldap.make_entry(dn) entry['objectclass'] = ['nsContainer', 'pkiCA'] entry.single_value['cn'] = 'CAcert' entry.single_value['cACertificate;binary'] = ca_cert ldap.add_entry(entry) else: force_write = False try: _cert_bin = entry['cACertificate;binary'] except ValueError: # BZ 1644874 # sometimes the cert is badly stored, twice encoded # force write to fix the value logger.debug('Fixing the value of cACertificate;binary ' 'in entry %s', entry.dn) force_write = True if force_write or b'' in entry['cACertificate;binary']: entry.single_value['cACertificate;binary'] = ca_cert ldap.update_entry(entry) return False, []
def install_step_1(standalone, replica_config, options, custodia): if replica_config is not None and not replica_config.setup_ca: return realm_name = options.realm_name host_name = options.host_name subject_base = options._subject_base basedn = ipautil.realm_to_suffix(realm_name) ca = cainstance.CAInstance( realm=realm_name, host_name=host_name, custodia=custodia ) ca.stop('pki-tomcat') # This is done within stopped_service context, which restarts CA ca.enable_client_auth_to_db() # Lightweight CA key retrieval is configured in step 1 instead # of CAInstance.configure_instance (which is invoked from step # 0) because kadmin_addprinc fails until krb5.conf is installed # by krb.create_instance. # ca.setup_lightweight_ca_key_retrieval() serverid = ipaldap.realm_to_serverid(realm_name) if standalone and replica_config is None: dirname = dsinstance.config_dirname(serverid) # Store the new IPA CA cert chain in DS NSS database and LDAP cadb = certs.CertDB( realm_name, nssdir=paths.PKI_TOMCAT_ALIAS_DIR, subject_base=subject_base) dsdb = certs.CertDB( realm_name, nssdir=dirname, subject_base=subject_base) cacert = cadb.get_cert_from_db('caSigningCert cert-pki-ca') nickname = certdb.get_ca_nickname(realm_name) trust_flags = certdb.IPA_CA_TRUST_FLAGS dsdb.add_cert(cacert, nickname, trust_flags) certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn, cacert, nickname, trust_flags, config_ipa=True, config_compat=True) # Store DS CA cert in Dogtag NSS database trust_flags = dict(reversed(dsdb.list_certs())) server_certs = dsdb.find_server_certs() trust_chain = dsdb.find_root_cert(server_certs[0][0])[:-1] nickname = trust_chain[-1] cert = dsdb.get_cert_from_db(nickname) cadb.add_cert(cert, nickname, trust_flags[nickname]) installutils.restart_dirsrv() ca.start('pki-tomcat') if standalone or replica_config is not None: # We need to restart apache as we drop a new config file in there services.knownservices.httpd.restart(capture_output=True) if standalone: # Install CA DNS records if bindinstance.dns_container_exists(basedn): bind = bindinstance.BindInstance() bind.update_system_records()
os.remove(csr_name) except: pass try: os.remove(cert_name) except: pass self.log.error('next_serial() failed: %s' % e) raise errors.CertificateOperationError(error=_('cannot obtain next serial number')) try: args = [ "/usr/bin/certutil", "-C", "-d", self.sec_dir, "-c", get_ca_nickname(api.env.realm), "-i", csr_name, "-o", cert_name, "-m", str(serialno), "-v", "60", "-1", "-5", "-6", "-a", "-f", self.pwd_file] self.log.debug("issue cert: %s" % str(args)) p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) p.stdin.write("0\n1\n2\n3\n9\ny\n")
def execute(self, **options): serverid = realm_to_serverid(self.api.env.realm) db = certs.CertDB(self.api.env.realm, nssdir=dsinstance.config_dirname(serverid)) ca_cert = None ca_enabled = self.api.Command.ca_is_enabled()['result'] if ca_enabled: ca_nickname = certdb.get_ca_nickname(self.api.env.realm) ca_subject = certstore.get_ca_subject(self.api.Backend.ldap2, self.api.env.container_ca, self.api.env.basedn) else: ca_nickname = None server_certs = db.find_server_certs() if server_certs: ca_chain = db.find_root_cert(server_certs[0][0])[:-1] if ca_chain: ca_nickname = ca_chain[-1] ldap = self.api.Backend.ldap2 for nickname, trust_flags in db.list_certs(): if trust_flags.has_key: continue cert = db.get_cert_from_db(nickname) subject = cert.subject if ca_enabled and subject == ca_subject: # When ca is enabled, we can have the IPA CA cert stored # in the nss db with a different nickname (for instance # when the server was installed with --subject to # customize the CA cert subject), but it must always be # stored in LDAP with the DN cn=$DOMAIN IPA CA # This is why we check the subject instead of the nickname here nickname = ca_nickname trust_flags = certdb.IPA_CA_TRUST_FLAGS trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags) dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) entry = ldap.make_entry(dn) try: certstore.init_ca_entry(entry, cert, nickname, trust, eku) except Exception as e: logger.warning("Failed to create entry for %s: %s", nickname, e) continue if nickname == ca_nickname: ca_cert = cert config = entry.setdefault('ipaConfigString', []) if ca_enabled: config.append('ipaCa') config.append('ipaCa') try: ldap.add_entry(entry) except errors.DuplicateEntry: if nickname == ca_nickname and ca_enabled: try: ldap.update_entry(entry) except errors.EmptyModlist: pass if ca_cert: dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) try: entry = ldap.get_entry(dn) except errors.NotFound: entry = ldap.make_entry(dn) entry['objectclass'] = ['nsContainer', 'pkiCA'] entry.single_value['cn'] = 'CAcert' entry.single_value['cACertificate;binary'] = ca_cert ldap.add_entry(entry) else: force_write = False try: _cert_bin = entry['cACertificate;binary'] except ValueError: # BZ 1644874 # sometimes the cert is badly stored, twice encoded # force write to fix the value logger.debug( 'Fixing the value of cACertificate;binary ' 'in entry %s', entry.dn) force_write = True if force_write or b'' in entry['cACertificate;binary']: entry.single_value['cACertificate;binary'] = ca_cert ldap.update_entry(entry) return False, []
def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file realm_name = options.realm_name host_name = options.host_name if replica_config is None: options._subject_base = options.subject_base options._ca_subject = options.ca_subject else: # during replica install, this gets invoked before local DS is # available, so use the remote api. _api = api if standalone else options._remote_api # for replica-install the knobs cannot be written, hence leading '_' options._subject_base = str(replica_config.subject_base) options._ca_subject = lookup_ca_subject(_api, options._subject_base) if replica_config is not None and not replica_config.setup_ca: return if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': raise ScriptError('A selfsign CA can not be added') if standalone and not options.skip_conncheck: principal = options.principal replica_conn_check( replica_config.ca_host_name, host_name, realm_name, True, replica_config.ca_ds_port, options.admin_password, principal=principal, ca_cert_file=options.ca_cert_file) if options.skip_schema_check: logger.info("Skipping CA DS schema check") return if standalone: if api.Command.ca_is_enabled()['result']: raise ScriptError( "One or more CA masters are already present in IPA realm " "'%s'.\nIf you wish to replicate CA to this host, please " "re-run 'ipa-ca-install'\nwith a replica file generated on " "an existing CA master as argument." % realm_name ) if options.external_cert_files: if not cainstance.is_step_one_done(): # This can happen if someone passes external_ca_file without # already having done the first stage of the CA install. raise ScriptError( "CA is not installed yet. To install with an external CA " "is a two-stage process.\nFirst run the installer with " "--external-ca.") external_cert_file, external_ca_file = installutils.load_external_cert( options.external_cert_files, options._ca_subject) elif options.external_ca: if cainstance.is_step_one_done(): raise ScriptError( "CA is already installed.\nRun the installer with " "--external-cert-file.") if os.path.isfile(paths.ROOT_IPA_CSR): raise ScriptError( "CA CSR file %s already exists.\nIn order to continue " "remove the file and run the installer again." % paths.ROOT_IPA_CSR) if not options.external_ca_type: options.external_ca_type = \ cainstance.ExternalCAType.GENERIC.value if options.external_ca_profile is not None: # check that profile is valid for the external ca type if options.external_ca_type \ not in options.external_ca_profile.valid_for: raise ScriptError( "External CA profile specification '{}' " "cannot be used with external CA type '{}'." .format( options.external_ca_profile.unparsed_input, options.external_ca_type) ) if not options.external_cert_files: if not cainstance.check_ports(): print( "IPA requires ports 8080 and 8443 for PKI, but one or more " "are currently in use." ) raise ScriptError("Aborting installation") if standalone: dirname = dsinstance.config_dirname( ipaldap.realm_to_serverid(realm_name)) cadb = certs.CertDB(realm_name, nssdir=paths.PKI_TOMCAT_ALIAS_DIR, subject_base=options._subject_base) dsdb = certs.CertDB( realm_name, nssdir=dirname, subject_base=options._subject_base) # Check that we can add our CA cert to DS and PKI NSS databases for db in (cadb, dsdb): if not db.exists(): continue for nickname, _trust_flags in db.list_certs(): if nickname == certdb.get_ca_nickname(realm_name): raise ScriptError( "Certificate with nickname %s is present in %s, " "cannot continue." % (nickname, db.secdir)) cert = db.get_cert_from_db(nickname) if not cert: continue subject = DN(cert.subject) if subject == DN(options._ca_subject): raise ScriptError( "Certificate with subject %s is present in %s, " "cannot continue." % (subject, db.secdir))
def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file realm_name = options.realm_name host_name = options.host_name subject_base = options.subject if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': sys.exit('A selfsign CA can not be added') if ((not options.promote and not ipautil.file_exists(replica_config.dir + "/cacert.p12"))): print('CA cannot be installed in CA-less setup.') sys.exit(1) if standalone and not options.skip_conncheck: principal = options.principal replica_conn_check( replica_config.master_host_name, host_name, realm_name, True, replica_config.ca_ds_port, options.admin_password, principal=principal, ca_cert_file=options.ca_cert_file) if options.skip_schema_check or options.promote: root_logger.info("Skipping CA DS schema check") else: cainstance.replica_ca_install_check(replica_config) return if standalone: if api.Command.ca_is_enabled()['result']: sys.exit( "One or more CA masters are already present in IPA realm " "'%s'.\nIf you wish to replicate CA to this host, please " "re-run 'ipa-ca-install'\nwith a replica file generated on " "an existing CA master as argument." % realm_name ) if options.external_cert_files: if not cainstance.is_step_one_done(): # This can happen if someone passes external_ca_file without # already having done the first stage of the CA install. print("CA is not installed yet. To install with an external CA " "is a two-stage process.\nFirst run the installer with " "--external-ca.") sys.exit(1) external_cert_file, external_ca_file = installutils.load_external_cert( options.external_cert_files, options.subject) elif options.external_ca: if cainstance.is_step_one_done(): print("CA is already installed.\nRun the installer with " "--external-cert-file.") sys.exit(1) if ipautil.file_exists(paths.ROOT_IPA_CSR): print(("CA CSR file %s already exists.\nIn order to continue " "remove the file and run the installer again." % paths.ROOT_IPA_CSR)) sys.exit(1) if not options.external_cert_files: if not cainstance.check_port(): print("IPA requires port 8443 for PKI but it is currently in use.") sys.exit("Aborting installation") if standalone: dirname = dsinstance.config_dirname( installutils.realm_to_serverid(realm_name)) cadb = certs.CertDB(realm_name, subject_base=subject_base) dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base) for db in (cadb, dsdb): for nickname, trust_flags in db.list_certs(): if nickname in (certdb.get_ca_nickname(realm_name), 'ipaCert', 'Signing-Cert'): print(("Certificate with nickname %s is present in %s, " "cannot continue." % (nickname, db.secdir))) sys.exit(1) cert = db.get_cert_from_db(nickname) if not cert: continue subject = DN(str(x509.get_subject(cert))) if subject in (DN('CN=Certificate Authority', subject_base), DN('CN=IPA RA', subject_base), DN('CN=Object Signing Cert', subject_base)): print(("Certificate with subject %s is present in %s, " "cannot continue." % (subject, db.secdir))) sys.exit(1)