Example #1
0
    def regenerate_ca_file(self, ca_file):
        dm_pwd_fd = ipautil.write_tmp_file(self.dirman_password)

        keydb_pwd = ""
        with open(paths.PKI_TOMCAT_PASSWORD_CONF) as f:
            for line in f.readlines():
                key, value = line.strip().split("=")
                if key == "internal":
                    keydb_pwd = value
                    break

        keydb_pwd_fd = ipautil.write_tmp_file(keydb_pwd)

        ipautil.run(
            [
                paths.PKCS12EXPORT,
                "-d",
                paths.PKI_TOMCAT_ALIAS_DIR,
                "-p",
                keydb_pwd_fd.name,
                "-w",
                dm_pwd_fd.name,
                "-o",
                ca_file,
            ]
        )
Example #2
0
def synconce_ntp(server_fqdn, debug=False):
    """
    Syncs time with specified server using ntpd.
    Primarily designed to be used before Kerberos setup
    to get time following the KDC time

    Returns True if sync was successful
    """
    ntpd = paths.NTPD
    if not os.path.exists(ntpd):
        return False

    # The ntpd command will never exit if it is unable to reach the
    # server, so timeout after 15 seconds.
    timeout = 15

    tmp_ntp_conf = ipautil.write_tmp_file('server %s' % server_fqdn)
    args = [paths.BIN_TIMEOUT, str(timeout), ntpd, '-qgc', tmp_ntp_conf.name]
    if debug:
        args.append('-d')
    try:
        logger.info('Attempting to sync time using ntpd.  '
                    'Will timeout after %d seconds', timeout)
        ipautil.run(args)
        return True
    except ipautil.CalledProcessError as e:
        if e.returncode == 124:
            logger.debug('Process did not complete before timeout')
        return False
Example #3
0
    def __create_instance(self):
        pent = pwd.getpwnam(DS_USER)

        self.backup_state("serverid", self.serverid)
        self.fstore.backup_file(paths.SYSCONFIG_DIRSRV)

        self.sub_dict['BASEDC'] = self.realm.split('.')[0].lower()
        base_txt = ipautil.template_str(BASE_TEMPLATE, self.sub_dict)
        root_logger.debug(base_txt)

        target_fname = paths.DIRSRV_BOOT_LDIF
        base_fd = open(target_fname, "w")
        base_fd.write(base_txt)
        base_fd.close()

        # Must be readable for dirsrv
        os.chmod(target_fname, 0440)
        os.chown(target_fname, pent.pw_uid, pent.pw_gid)

        inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict)
        root_logger.debug("writing inf template")
        inf_fd = ipautil.write_tmp_file(inf_txt)
        inf_txt = re.sub(r"RootDNPwd=.*\n", "", inf_txt)
        root_logger.debug(inf_txt)
        if ipautil.file_exists(paths.SETUP_DS_PL):
            args = [paths.SETUP_DS_PL, "--silent", "--logfile", "-", "-f", inf_fd.name]
            root_logger.debug("calling setup-ds.pl")
        else:
            args = [paths.DS_NEWINST_PL, inf_fd.name]
            root_logger.debug("calling ds_newinst.pl")
        try:
            ipautil.run(args)
            root_logger.debug("completed creating ds instance")
        except ipautil.CalledProcessError, e:
            root_logger.critical("failed to create ds instance %s" % e)
Example #4
0
    def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb):
        # create a temp nssdb
        with NSSDatabase() as tempnssdb:
            db_password = ipautil.ipa_generate_password()
            db_pwdfile = ipautil.write_tmp_file(db_password)
            tempnssdb.create_db(db_pwdfile.name)

            # import the PKCS12 file, then delete all CA certificates
            # this leaves only the server certs in the temp db
            tempnssdb.import_pkcs12(
                pkcs12_filename, db_pwdfile.name, pkcs12_pin)
            for nickname, flags in tempnssdb.list_certs():
                if 'u' not in flags:
                    while tempnssdb.has_nickname(nickname):
                        tempnssdb.delete_cert(nickname)

            # import all the CA certs from nssdb into the temp db
            for nickname, flags in nssdb.list_certs():
                if 'u' not in flags:
                    cert = nssdb.get_cert_from_db(nickname)
                    tempnssdb.add_cert(cert, nickname, flags)

            # now get the server certs from tempnssdb and check their validity
            try:
                for nick, flags in tempnssdb.find_server_certs():
                    tempnssdb.verify_server_cert_validity(nick, api.env.host)
            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))
Example #5
0
    def validate_options(self):
        options = self.options
        super(Backup, self).validate_options(needs_root=True)
        installutils.check_server_configuration()

        if options.gpg_keyring is not None:
            print(
                "--gpg-keyring is no longer supported, use GNUPGHOME "
                "environment variable to use a custom GnuPG2 directory.",
                file=sys.stderr
            )
            options.gpg = True

        if options.online and not options.data_only:
            self.option_parser.error("You cannot specify --online "
                "without --data")

        if options.gpg:
            tmpfd = write_tmp_file('encryptme')
            newfile = encrypt_file(tmpfd.name, False)
            os.unlink(newfile)

        if options.data_only and options.logs:
            self.option_parser.error("You cannot specify --data "
                "with --logs")
Example #6
0
    def __create_instance(self):
        pent = pwd.getpwnam(DS_USER)

        self.backup_state("serverid", self.serverid)
        self.fstore.backup_file("/etc/sysconfig/dirsrv")

        self.sub_dict['BASEDC'] = self.realm.split('.')[0].lower()
        base_txt = ipautil.template_str(BASE_TEMPLATE, self.sub_dict)
        root_logger.debug(base_txt)

        target_fname = '/var/lib/dirsrv/boot.ldif'
        base_fd = open(target_fname, "w")
        base_fd.write(base_txt)
        base_fd.close()

        # Must be readable for dirsrv
        os.chmod(target_fname, 0440)
        os.chown(target_fname, pent.pw_uid, pent.pw_gid)

        inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict)
        root_logger.debug("writing inf template")
        inf_fd = ipautil.write_tmp_file(inf_txt)
        inf_txt = re.sub(r"RootDNPwd=.*\n", "", inf_txt)
        root_logger.debug(inf_txt)
        if ipautil.file_exists("/usr/sbin/setup-ds.pl"):
            args = ["/usr/sbin/setup-ds.pl", "--silent", "--logfile", "-", "-f", inf_fd.name]
            root_logger.debug("calling setup-ds.pl")
        else:
            args = ["/usr/bin/ds_newinst.pl", inf_fd.name]
            root_logger.debug("calling ds_newinst.pl")
        try:
            ipautil.run(args)
            root_logger.debug("completed creating ds instance")
        except ipautil.CalledProcessError, e:
            root_logger.critical("failed to create ds instance %s" % e)
Example #7
0
    def execute(self, ldapuri, bindpw, **options):
        ldap = self.api.Backend.ldap2
        self.normalize_options(options)
        config = ldap.get_ipa_config()

        ds_base_dn = options.get('basedn')
        if ds_base_dn is not None:
            assert isinstance(ds_base_dn, DN)

        # check if migration mode is enabled
        if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE':
            return dict(result={}, failed={}, enabled=False, compat=True)

        # connect to DS
        ds_ldap = ldap2(self.api, ldap_uri=ldapuri)

        cacert = None
        if options.get('cacertfile') is not None:
            # store CA cert into file
            tmp_ca_cert_f = write_tmp_file(options['cacertfile'])
            cacert = tmp_ca_cert_f.name

            # start TLS connection
            ds_ldap.connect(bind_dn=options['binddn'], bind_pw=bindpw,
                            cacert=cacert)

            tmp_ca_cert_f.close()
        else:
            ds_ldap.connect(bind_dn=options['binddn'], bind_pw=bindpw)

        # check whether the compat plugin is enabled
        if not options.get('compat'):
            try:
                ldap.get_entry(DN(('cn', 'compat'), (api.env.basedn)))
                return dict(result={}, failed={}, enabled=True, compat=False)
            except errors.NotFound:
                pass

        if not ds_base_dn:
            # retrieve base DN from remote LDAP server
            entries, _truncated = ds_ldap.find_entries(
                '', ['namingcontexts', 'defaultnamingcontext'], DN(''),
                ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0,
            )
            if 'defaultnamingcontext' in entries[0]:
                ds_base_dn = DN(entries[0]['defaultnamingcontext'][0])
                assert isinstance(ds_base_dn, DN)
            else:
                try:
                    ds_base_dn = DN(entries[0]['namingcontexts'][0])
                    assert isinstance(ds_base_dn, DN)
                except (IndexError, KeyError) as e:
                    raise Exception(str(e))

        # migrate!
        (migrated, failed) = self.migrate(
            ldap, config, ds_ldap, ds_base_dn, options
        )

        return dict(result=migrated, failed=failed, enabled=True, compat=True)
Example #8
0
 def import_pkcs12(self, pkcs12_filename, pkcs12_passwd=None):
     args = [
         "-i", pkcs12_filename,
         "-k", self.pwd_file,
         "-v"
     ]
     pkcs12_password_file = None
     if pkcs12_passwd is not None:
         pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n')
         args.extend(["-w", pkcs12_password_file.name])
     try:
         self.run_pk12util(args)
     except ipautil.CalledProcessError as e:
         if e.returncode == 17 or e.returncode == 18:
             raise Pkcs12ImportIncorrectPasswordError(
                 "incorrect password for pkcs#12 file %s" % pkcs12_filename)
         elif e.returncode == 10:
             raise Pkcs12ImportOpenError(
                 "Failed to open %s" % pkcs12_filename)
         else:
             raise Pkcs12ImportUnknownError(
                 "unknown error import pkcs#12 file %s" %
                 pkcs12_filename)
     finally:
         if pkcs12_password_file is not None:
             pkcs12_password_file.close()
Example #9
0
    def execute(self, ldapuri, bindpw, **options):
        ldap = self.api.Backend.ldap2
        self.normalize_options(options)
        config = ldap.get_ipa_config()[1]

        ds_base_dn = options.get('basedn')
        if ds_base_dn is not None:
            assert isinstance(ds_base_dn, DN)

        # check if migration mode is enabled
        if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE':
            return dict(result={}, failed={}, enabled=False, compat=True)

        # connect to DS
        ds_ldap = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='')

        cacert = None
        if options.get('cacertfile') is not None:
            #store CA cert into file
            tmp_ca_cert_f = write_tmp_file(options['cacertfile'])
            cacert = tmp_ca_cert_f.name

            #start TLS connection
            ds_ldap.connect(bind_dn=options['binddn'], bind_pw=bindpw,
                tls_cacertfile=cacert)

            tmp_ca_cert_f.close()
        else:
            ds_ldap.connect(bind_dn=options['binddn'], bind_pw=bindpw)

        #check whether the compat plugin is enabled
        if not options.get('compat'):
            try:
                (dn,check_compat) = ldap.get_entry(_compat_dn)
                assert isinstance(dn, DN)
                if check_compat is not None and \
                        check_compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'on':
                    return dict(result={}, failed={}, enabled=True, compat=False)
            except errors.NotFound:
                pass

        if not ds_base_dn:
            # retrieve base DN from remote LDAP server
            entries, truncated = ds_ldap.find_entries(
                '', ['namingcontexts', 'defaultnamingcontext'], DN(''),
                ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0,
            )
            if 'defaultnamingcontext' in entries[0][1]:
                ds_base_dn = DN(entries[0][1]['defaultnamingcontext'][0])
                assert isinstance(ds_base_dn, DN)
            else:
                try:
                    ds_base_dn = DN(entries[0][1]['namingcontexts'][0])
                    assert isinstance(ds_base_dn, DN)
                except (IndexError, KeyError), e:
                    raise StandardError(str(e))
Example #10
0
    def install(self):
        print("Installing CA certificate, please wait")

        options = self.options
        cert_filename = self.args[1]

        nss_cert = None
        try:
            try:
                nss_cert = x509.load_certificate_from_file(cert_filename)
            except IOError as e:
                raise admintool.ScriptError(
                    "Can't open \"%s\": %s" % (cert_filename, e))
            except (TypeError, NSPRError, ValueError) as e:
                raise admintool.ScriptError("Not a valid certificate: %s" % e)
            subject = nss_cert.subject
            cert = nss_cert.der_data
        finally:
            del nss_cert

        nickname = options.nickname or str(subject)

        ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2,
                                              api.env.basedn,
                                              api.env.realm,
                                              False)

        with certs.NSSDatabase() as tmpdb:
            pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
            tmpdb.create_db(pw.name)
            tmpdb.add_cert(cert, nickname, 'C,,')
            for ca_cert, ca_nickname, ca_trust_flags in ca_certs:
                tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags)

            try:
                tmpdb.verify_ca_cert_validity(nickname)
            except ValueError as e:
                raise admintool.ScriptError(
                    "Not a valid CA certificate: %s (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)" % e)

        trust_flags = options.trust_flags
        if ((set(trust_flags) - set(',CPTcgpuw')) or
            len(trust_flags.split(',')) != 3):
            raise admintool.ScriptError("Invalid trust flags")

        try:
            certstore.put_ca_cert_nss(
                api.Backend.ldap2, api.env.basedn, cert, nickname, trust_flags)
        except ValueError as e:
            raise admintool.ScriptError(
                "Failed to install the certificate: %s" % e)

        print("CA certificate successfully installed")
Example #11
0
    def regenerate_ca_file(self, ca_file):
        dm_pwd_fd = ipautil.write_tmp_file(self.dirman_password)

        keydb_pwd = ''
        with open(paths.PKI_TOMCAT_PASSWORD_CONF) as f:
            for line in f.readlines():
                key, value = line.strip().split('=')
                if key == 'internal':
                    keydb_pwd = value
                    break

        keydb_pwd_fd = ipautil.write_tmp_file(keydb_pwd)

        ipautil.run([
            paths.PKCS12EXPORT,
            '-d', paths.PKI_TOMCAT_ALIAS_DIR,
            '-p', keydb_pwd_fd.name,
            '-w', dm_pwd_fd.name,
            '-o', ca_file
        ])
Example #12
0
    def regenerate_ca_file(self, ca_file):
        dm_pwd_fd = ipautil.write_tmp_file(self.dirman_password)

        keydb_pwd = ''
        with open('/etc/pki/pki-tomcat/password.conf') as f:
            for line in f.readlines():
                key, value = line.strip().split('=')
                if key == 'internal':
                    keydb_pwd = value
                    break

        keydb_pwd_fd = ipautil.write_tmp_file(keydb_pwd)

        ipautil.run([
            '/usr/bin/PKCS12Export',
            '-d', '/etc/pki/pki-tomcat/alias/',
            '-p', keydb_pwd_fd.name,
            '-w', dm_pwd_fd.name,
            '-o', ca_file
        ])
Example #13
0
    def _ldap_mod(self, ldif, sub_dict=None, raise_on_err=False):
        pw_name = None
        fd = None
        path = ipautil.SHARE_DIR + ldif
        nologlist = []

        if sub_dict is not None:
            txt = ipautil.template_file(path, sub_dict)
            fd = ipautil.write_tmp_file(txt)
            path = fd.name

            # do not log passwords
            if 'PASSWORD' in sub_dict:
                nologlist.append(sub_dict['PASSWORD'])
            if 'RANDOM_PASSWORD' in sub_dict:
                nologlist.append(sub_dict['RANDOM_PASSWORD'])

        args = [paths.LDAPMODIFY, "-v", "-f", path]

        # As we always connect to the local host,
        # use URI of admin connection
        if not self.admin_conn:
            self.ldap_connect()
        args += ["-H", self.admin_conn.ldap_uri]

        # If DM password is available, use it
        if self.dm_password:
            [pw_fd, pw_name] = tempfile.mkstemp()
            os.write(pw_fd, self.dm_password)
            os.close(pw_fd)
            auth_parms = ["-x", "-D", "cn=Directory Manager", "-y", pw_name]
        # Use GSSAPI auth when not using DM password or not being root
        elif os.getegid() != 0:
            auth_parms = ["-Y", "GSSAPI"]
        # Default to EXTERNAL auth mechanism
        else:
            auth_parms = ["-Y", "EXTERNAL"]

        args += auth_parms

        try:
            try:
                ipautil.run(args, nolog=nologlist)
            except ipautil.CalledProcessError as e:
                if raise_on_err:
                    raise
                root_logger.critical("Failed to load %s: %s" % (ldif, str(e)))
        finally:
            if pw_name:
                os.remove(pw_name)

        if fd is not None:
            fd.close()
 def export_ra_pkcs12(self):
     if (os.path.exists(paths.RA_AGENT_PEM) and
        os.path.exists(paths.RA_AGENT_KEY)):
         with ipautil.write_tmp_file(self.dirman_password) as f:
             ipautil.run([
                 paths.OPENSSL,
                 "pkcs12", "-export",
                 "-inkey", paths.RA_AGENT_KEY,
                 "-in", paths.RA_AGENT_PEM,
                 "-out", os.path.join(self.dir, "ra.p12"),
                 "-passout", "file:{pwfile}".format(pwfile=f.name)
             ])
Example #15
0
    def _ldap_mod(self, ldif, sub_dict=None, raise_on_err=True,
                  ldap_uri=None, dm_password=None):
        pw_name = None
        fd = None
        path = os.path.join(paths.USR_SHARE_IPA_DIR, ldif)
        nologlist = []

        if sub_dict is not None:
            txt = ipautil.template_file(path, sub_dict)
            fd = ipautil.write_tmp_file(txt)
            path = fd.name

            # do not log passwords
            if 'PASSWORD' in sub_dict:
                nologlist.append(sub_dict['PASSWORD'])
            if 'RANDOM_PASSWORD' in sub_dict:
                nologlist.append(sub_dict['RANDOM_PASSWORD'])

        args = [paths.LDAPMODIFY, "-v", "-f", path]

        # As we always connect to the local host,
        # use URI of admin connection
        if not ldap_uri:
            ldap_uri = api.Backend.ldap2.ldap_uri

        args += ["-H", ldap_uri]

        if dm_password:
            with tempfile.NamedTemporaryFile(
                    mode='w', delete=False) as pw_file:
                pw_file.write(dm_password)
                pw_name = pw_file.name
            auth_parms = ["-x", "-D", "cn=Directory Manager", "-y", pw_name]
        # Use GSSAPI auth when not using DM password or not being root
        elif os.getegid() != 0:
            auth_parms = ["-Y", "GSSAPI"]
        # Default to EXTERNAL auth mechanism
        else:
            auth_parms = ["-Y", "EXTERNAL"]

        args += auth_parms

        try:
            try:
                ipautil.run(args, nolog=nologlist)
            except ipautil.CalledProcessError as e:
                root_logger.critical("Failed to load %s: %s" % (ldif, str(e)))
                if raise_on_err:
                    raise
        finally:
            if pw_name:
                os.remove(pw_name)
Example #16
0
def install_key_from_p12(
        p12_fname, p12_passwd, pem_fname, out_passwd_fname=None):
    pwd = ipautil.write_tmp_file(p12_passwd)
    args = [
        paths.OPENSSL, "pkcs12", "-nocerts",
        "-in", p12_fname, "-out", pem_fname,
        "-passin", "file:" + pwd.name]
    if out_passwd_fname is not None:
        args.extend(['-passout', 'file:{}'.format(out_passwd_fname)])
    else:
        args.append('-nodes')

    ipautil.run(args, umask=0o077)
Example #17
0
    def execute(self, ldapuri, bindpw, **options):
        ldap = self.api.Backend.ldap2
        self.normalize_options(options)
        config = ldap.get_ipa_config()

        ds_base_dn = options.get("basedn")
        if ds_base_dn is not None:
            assert isinstance(ds_base_dn, DN)

        # check if migration mode is enabled
        if config.get("ipamigrationenabled", ("FALSE",))[0] == "FALSE":
            return dict(result={}, failed={}, enabled=False, compat=True)

        # connect to DS
        ds_ldap = ldap2(self.api, ldap_uri=ldapuri)

        cacert = None
        if options.get("cacertfile") is not None:
            # store CA cert into file
            tmp_ca_cert_f = write_tmp_file(options["cacertfile"])
            cacert = tmp_ca_cert_f.name

            # start TLS connection
            ds_ldap.connect(bind_dn=options["binddn"], bind_pw=bindpw, tls_cacertfile=cacert)

            tmp_ca_cert_f.close()
        else:
            ds_ldap.connect(bind_dn=options["binddn"], bind_pw=bindpw)

        # check whether the compat plugin is enabled
        if not options.get("compat"):
            try:
                ldap.get_entry(DN(("cn", "compat"), (api.env.basedn)))
                return dict(result={}, failed={}, enabled=True, compat=False)
            except errors.NotFound:
                pass

        if not ds_base_dn:
            # retrieve base DN from remote LDAP server
            entries, truncated = ds_ldap.find_entries(
                "", ["namingcontexts", "defaultnamingcontext"], DN(""), ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0
            )
            if "defaultnamingcontext" in entries[0]:
                ds_base_dn = DN(entries[0]["defaultnamingcontext"][0])
                assert isinstance(ds_base_dn, DN)
            else:
                try:
                    ds_base_dn = DN(entries[0]["namingcontexts"][0])
                    assert isinstance(ds_base_dn, DN)
                except (IndexError, KeyError), e:
                    raise StandardError(str(e))
Example #18
0
def synconce_ntp(server_fqdn):
    """
    Syncs time with specified server using ntpd.
    Primarily designed to be used before Kerberos setup
    to get time following the KDC time

    Returns True if sync was successful
    """
    ntpd = '/usr/sbin/ntpd'
    if not os.path.exists(ntpd):
        return False

    tmp_ntp_conf = ipautil.write_tmp_file('server %s' % server_fqdn)
    try:
        ipautil.run([ntpd, '-qgc', tmp_ntp_conf.name])
        return True
    except ipautil.CalledProcessError:
        return False
Example #19
0
def install_check(api, replica_config, options):
    if replica_config is not None and not replica_config.setup_kra:
        return

    kra = krainstance.KRAInstance(api.env.realm)
    if kra.is_installed():
        raise RuntimeError("KRA is already installed.")

    if not options.setup_ca:
        if cainstance.is_ca_installed_locally():
            if api.env.dogtag_version >= 10:
                # correct dogtag version of CA installed
                pass
            else:
                raise RuntimeError(
                    "Dogtag must be version 10.2 or above to install KRA")
        else:
            raise RuntimeError(
                "Dogtag CA is not installed.  Please install the CA first")

    if replica_config is not None:
        if not api.Command.kra_is_enabled()['result']:
            raise RuntimeError(
                "KRA is not installed on the master system. Please use "
                "'ipa-kra-install' command to install the first instance.")

        if options.promote:
            return

        with certdb.NSSDatabase() as tmpdb:
            pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
            tmpdb.create_db(pw.name)
            tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name,
                                replica_config.dirman_password)
            kra_cert_nicknames = [
                "storageCert cert-pki-kra", "transportCert cert-pki-kra",
                "auditSigningCert cert-pki-kra"
            ]
            if not all(tmpdb.has_nickname(nickname)
                       for nickname in kra_cert_nicknames):
                raise RuntimeError("Missing KRA certificates, please create a "
                                   "new replica file.")
Example #20
0
def pkcs12_to_certkeys(p12_fname, p12_passwd=None):
    """
    Deserializes pkcs12 file to python objects

    :param p12_fname: A PKCS#12 filename
    :param p12_passwd: Optional password for the pkcs12_fname file
    """
    args = [paths.OPENSSL, "pkcs12", "-in", p12_fname, "-nodes"]
    if p12_passwd:
        pwd = ipautil.write_tmp_file(p12_passwd)
        args.extend(["-passin", "file:{fname}".format(fname=pwd.name)])
    else:
        args.extend(["-passin", "pass:"])

    pems = ipautil.run(args, capture_output=True).raw_output

    certs = x509.load_certificate_list(pems)
    priv_keys = x509.load_private_key_list(pems)

    return (certs, priv_keys)
Example #21
0
    def __create_instance(self):
        pent = pwd.getpwnam(DS_USER)

        self.backup_state("serverid", self.serverid)
        self.fstore.backup_file(paths.SYSCONFIG_DIRSRV)

        self.sub_dict['BASEDC'] = self.realm.split('.')[0].lower()
        base_txt = ipautil.template_str(BASE_TEMPLATE, self.sub_dict)
        logger.debug("%s", base_txt)

        target_fname = paths.DIRSRV_BOOT_LDIF
        base_fd = open(target_fname, "w")
        base_fd.write(base_txt)
        base_fd.close()

        # Must be readable for dirsrv
        os.chmod(target_fname, 0o440)
        os.chown(target_fname, pent.pw_uid, pent.pw_gid)

        inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict)
        logger.debug("writing inf template")
        inf_fd = ipautil.write_tmp_file(inf_txt)
        inf_txt = re.sub(r"RootDNPwd=.*\n", "", inf_txt)
        logger.debug("%s", inf_txt)
        args = [
            paths.SETUP_DS_PL, "--silent",
            "--logfile", "-",
            "-f", inf_fd.name,
        ]
        logger.debug("calling setup-ds.pl")
        try:
            ipautil.run(args)
            logger.debug("completed creating DS instance")
        except ipautil.CalledProcessError as e:
            raise RuntimeError("failed to create DS instance %s" % e)

        # check for open port 389 from now on
        self.open_ports.append(389)

        inf_fd.close()
        os.remove(paths.DIRSRV_BOOT_LDIF)
Example #22
0
    def migrate_to_mod_ssl(self):
        """For upgrades only, migrate from mod_nss to mod_ssl"""
        db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR)
        nickname = self.get_mod_nss_nickname()
        with tempfile.NamedTemporaryFile() as temp:
            pk12_password = ipautil.ipa_generate_password()
            pk12_pwdfile = ipautil.write_tmp_file(pk12_password)
            db.export_pkcs12(temp.name, pk12_pwdfile.name, nickname)
            certs.install_pem_from_p12(temp.name,
                                       pk12_password,
                                       paths.HTTPD_CERT_FILE)

            passwd_fname = paths.HTTPD_PASSWD_FILE_FMT.format(
                            host=api.env.host)
            with open(passwd_fname, 'wb') as passwd_file:
                os.fchmod(passwd_file.fileno(), 0o600)
                passwd_file.write(
                    ipautil.ipa_generate_password().encode('utf-8'))

            certs.install_key_from_p12(temp.name,
                                       pk12_password,
                                       paths.HTTPD_KEY_FILE,
                                       out_passwd_fname=passwd_fname)

        self.backup_ssl_conf()
        self.configure_mod_ssl_certs()
        self.set_mod_ssl_protocol()
        self.set_mod_ssl_logdir()
        self.__add_include()

        self.cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)

        if self.ca_is_configured:
            db.untrack_server_cert(nickname)
            self.start_tracking_certificates()

        # remove nickname and CA certs from NSS db

        self.disable_nss_conf()
Example #23
0
 def import_pkcs12(self, pkcs12_filename, pkcs12_passwd=None):
     args = [PK12UTIL, "-d", self.secdir,
             "-i", pkcs12_filename,
             "-k", self.pwd_file, '-v']
     pkcs12_password_file = None
     if pkcs12_passwd is not None:
         pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n')
         args = args + ["-w", pkcs12_password_file.name]
     try:
         ipautil.run(args)
     except ipautil.CalledProcessError as e:
         if e.returncode == 17:
             raise RuntimeError("incorrect password for pkcs#12 file %s" %
                 pkcs12_filename)
         elif e.returncode == 10:
             raise RuntimeError("Failed to open %s" % pkcs12_filename)
         else:
             raise RuntimeError("unknown error import pkcs#12 file %s" %
                 pkcs12_filename)
     finally:
         if pkcs12_password_file is not None:
             pkcs12_password_file.close()
Example #24
0
    def validate_options(self):
        options = self.options
        super(Backup, self).validate_options(needs_root=True)
        installutils.check_server_configuration()

        if options.gpg_keyring is not None:
            if not os.path.exists(options.gpg_keyring + '.pub'):
                raise admintool.ScriptError('No such key %s' %
                    options.gpg_keyring)
            options.gpg = True

        if options.online and not options.data_only:
            self.option_parser.error("You cannot specify --online "
                "without --data")

        if options.gpg:
            tmpfd = write_tmp_file('encryptme')
            newfile = encrypt_file(tmpfd.name, options.gpg_keyring, False)
            os.unlink(newfile)

        if options.data_only and options.logs:
            self.option_parser.error("You cannot specify --data "
                "with --logs")
Example #25
0
def synconce_ntp(server_fqdn):
    """
    Syncs time with specified server using ntpd.
    Primarily designed to be used before Kerberos setup
    to get time following the KDC time

    Returns True if sync was successful
    """
    ntpd = paths.NTPD
    if not os.path.exists(ntpd):
        return False

    tmp_ntp_conf = ipautil.write_tmp_file('server %s' % server_fqdn)
    try:
        # The ntpd command will never exit if it is unable to reach the
        # server, so timeout after 15 seconds.
        timeout = 15
        root_logger.info('Attempting to sync time using ntpd.  '
                         'Will timeout after %d seconds' % timeout)
        ipautil.run([ntpd, '-qgc', tmp_ntp_conf.name], timeout=timeout)
        return True
    except ipautil.CalledProcessError:
        return False
Example #26
0
 def export_pkcs12(self, nickname, pkcs12_filename, pkcs12_passwd=None):
     args = [
         "-o", pkcs12_filename,
         "-n", nickname,
         "-k", self.pwd_file
     ]
     pkcs12_password_file = None
     if pkcs12_passwd is not None:
         pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n')
         args.extend(["-w", pkcs12_password_file.name])
     try:
         self.run_pk12util(args)
     except ipautil.CalledProcessError as e:
         if e.returncode == 17:
             raise RuntimeError("incorrect password for pkcs#12 file %s" %
                                pkcs12_filename)
         elif e.returncode == 10:
             raise RuntimeError("Failed to open %s" % pkcs12_filename)
         else:
             raise RuntimeError("unknown error exporting pkcs#12 file %s" %
                                pkcs12_filename)
     finally:
         if pkcs12_password_file is not None:
             pkcs12_password_file.close()
Example #27
0
 def test_from_json_file(self):
     file = write_tmp_file(json.dumps(self.get_input_dict()))
     conf = config.Config.from_env({'IPATEST_JSON_CONFIG': file.name})
     assert_deepequal(self.get_output_dict(), conf.to_dict())
     self.check_config(conf)
Example #28
0
def install_key_from_p12(p12_fname, p12_passwd, pem_fname):
    pwd = ipautil.write_tmp_file(p12_passwd)
    ipautil.run([paths.OPENSSL, "pkcs12", "-nodes", "-nocerts",
                 "-in", p12_fname, "-out", pem_fname,
                 "-passin", "file:" + pwd.name],
                umask=0o077)
Example #29
0
    def import_files(self,
                     files,
                     db_password_filename,
                     import_keys=False,
                     key_password=None,
                     key_nickname=None):
        """
        Import certificates and a single private key from multiple files

        The files may be in PEM and DER certificate, PKCS#7 certificate chain,
        PKCS#8 and raw private key and PKCS#12 formats.

        :param files: Names of files to import
        :param db_password_filename: Name of file containing the database
            password
        :param import_keys: Whether to import private keys
        :param key_password: Password to decrypt private keys
        :param key_nickname: Nickname of the private key to import from PKCS#12
            files
        """
        key_file = None
        extracted_key = None
        extracted_certs = ''

        for filename in files:
            try:
                with open(filename, 'rb') as f:
                    data = f.read()
            except IOError as e:
                raise RuntimeError("Failed to open %s: %s" %
                                   (filename, e.strerror))

            # Try to parse the file as PEM file
            matches = list(
                re.finditer(r'-----BEGIN (.+?)-----(.*?)-----END \1-----',
                            data, re.DOTALL))
            if matches:
                loaded = False
                for match in matches:
                    body = match.group()
                    label = match.group(1)
                    line = len(data[:match.start() + 1].splitlines())

                    if label in ('CERTIFICATE', 'X509 CERTIFICATE',
                                 'X.509 CERTIFICATE'):
                        try:
                            x509.load_certificate(match.group(2))
                        except NSPRError as e:
                            if label != 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                                continue
                        else:
                            extracted_certs += body + '\n'
                            loaded = True
                            continue

                    if label in ('PKCS7', 'PKCS #7 SIGNED DATA',
                                 'CERTIFICATE'):
                        args = [
                            paths.OPENSSL,
                            'pkcs7',
                            '-print_certs',
                        ]
                        try:
                            result = ipautil.run(args,
                                                 stdin=body,
                                                 capture_output=True)
                        except ipautil.CalledProcessError as e:
                            if label == 'CERTIFICATE':
                                root_logger.warning(
                                    "Skipping certificate in %s at line %s: %s",
                                    filename, line, e)
                            else:
                                root_logger.warning(
                                    "Skipping PKCS#7 in %s at line %s: %s",
                                    filename, line, e)
                            continue
                        else:
                            extracted_certs += result.output + '\n'
                            loaded = True
                            continue

                    if label in ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY',
                                 'RSA PRIVATE KEY', 'DSA PRIVATE KEY',
                                 'EC PRIVATE KEY'):
                        if not import_keys:
                            continue

                        if key_file:
                            raise RuntimeError(
                                "Can't load private key from both %s and %s" %
                                (key_file, filename))

                        args = [
                            paths.OPENSSL,
                            'pkcs8',
                            '-topk8',
                            '-passout',
                            'file:' + db_password_filename,
                        ]
                        if ((label != 'PRIVATE KEY' and key_password)
                                or label == 'ENCRYPTED PRIVATE KEY'):
                            key_pwdfile = ipautil.write_tmp_file(key_password)
                            args += [
                                '-passin',
                                'file:' + key_pwdfile.name,
                            ]
                        try:
                            result = ipautil.run(args,
                                                 stdin=body,
                                                 capture_output=True)
                        except ipautil.CalledProcessError as e:
                            root_logger.warning(
                                "Skipping private key in %s at line %s: %s",
                                filename, line, e)
                            continue
                        else:
                            extracted_key = result.output
                            key_file = filename
                            loaded = True
                            continue
                if loaded:
                    continue
                raise RuntimeError("Failed to load %s" % filename)

            # Try to load the file as DER certificate
            try:
                x509.load_certificate(data, x509.DER)
            except NSPRError:
                pass
            else:
                data = x509.make_pem(base64.b64encode(data))
                extracted_certs += data + '\n'
                continue

            # Try to import the file as PKCS#12 file
            if import_keys:
                try:
                    self.import_pkcs12(filename, db_password_filename,
                                       key_password)
                except RuntimeError:
                    pass
                else:
                    if key_file:
                        raise RuntimeError(
                            "Can't load private key from both %s and %s" %
                            (key_file, filename))
                    key_file = filename

                    server_certs = self.find_server_certs()
                    if key_nickname:
                        for nickname, _trust_flags in server_certs:
                            if nickname == key_nickname:
                                break
                        else:
                            raise RuntimeError(
                                "Server certificate \"%s\" not found in %s" %
                                (key_nickname, filename))
                    else:
                        if len(server_certs) > 1:
                            raise RuntimeError(
                                "%s server certificates found in %s, "
                                "expecting only one" %
                                (len(server_certs), filename))

                    continue

            raise RuntimeError("Failed to load %s" % filename)

        if import_keys and not key_file:
            raise RuntimeError("No server certificates found in %s" %
                               (', '.join(files)))

        nss_certs = x509.load_certificate_list(extracted_certs)
        nss_cert = None
        for nss_cert in nss_certs:
            nickname = str(nss_cert.subject)
            self.add_cert(nss_cert.der_data, nickname, ',,')
        del nss_certs, nss_cert

        if extracted_key:
            in_file = ipautil.write_tmp_file(extracted_certs + extracted_key)
            out_file = tempfile.NamedTemporaryFile()
            out_password = ipautil.ipa_generate_password()
            out_pwdfile = ipautil.write_tmp_file(out_password)
            args = [
                paths.OPENSSL,
                'pkcs12',
                '-export',
                '-in',
                in_file.name,
                '-out',
                out_file.name,
                '-passin',
                'file:' + db_password_filename,
                '-passout',
                'file:' + out_pwdfile.name,
            ]
            try:
                ipautil.run(args)
            except ipautil.CalledProcessError as e:
                raise RuntimeError(
                    "No matching certificate found for private key from %s" %
                    key_file)

            self.import_pkcs12(out_file.name, db_password_filename,
                               out_password)
Example #30
0
 def test_from_json_file(self):
     file = write_tmp_file(json.dumps(self.get_input_dict()))
     conf = config.Config.from_env({'IPATEST_JSON_CONFIG': file.name})
     assert_deepequal(self.get_output_dict(), conf.to_dict())
     self.check_config(conf)
Example #31
0
    def import_files(self,
                     files,
                     import_keys=False,
                     key_password=None,
                     key_nickname=None):
        """
        Import certificates and a single private key from multiple files

        The files may be in PEM and DER certificate, PKCS#7 certificate chain,
        PKCS#8 and raw private key and PKCS#12 formats.

        :param files: Names of files to import
        :param import_keys: Whether to import private keys
        :param key_password: Password to decrypt private keys
        :param key_nickname: Nickname of the private key to import from PKCS#12
            files
        """
        key_file = None
        extracted_key = None
        extracted_certs = []

        for filename in files:
            try:
                with open(filename, 'rb') as f:
                    data = f.read()
            except IOError as e:
                raise RuntimeError("Failed to open %s: %s" %
                                   (filename, e.strerror))

            # Try to parse the file as PEM file
            matches = list(
                re.finditer(br'-----BEGIN (.+?)-----(.*?)-----END \1-----',
                            data, re.DOTALL))
            if matches:
                loaded = False
                for match in matches:
                    body = match.group()
                    label = match.group(1)
                    line = len(data[:match.start() + 1].splitlines())

                    if label in (b'CERTIFICATE', b'X509 CERTIFICATE',
                                 b'X.509 CERTIFICATE'):
                        try:
                            cert = x509.load_pem_x509_certificate(body)
                        except ValueError as e:
                            if label != b'CERTIFICATE':
                                logger.warning(
                                    "Skipping certificate in %s at line %s: "
                                    "%s", filename, line, e)
                                continue
                        else:
                            extracted_certs.append(cert)
                            loaded = True
                            continue

                    if label in (b'PKCS7', b'PKCS #7 SIGNED DATA',
                                 b'CERTIFICATE'):
                        try:
                            certs = x509.pkcs7_to_certs(body)
                        except ipautil.CalledProcessError as e:
                            if label == b'CERTIFICATE':
                                logger.warning(
                                    "Skipping certificate in %s at line %s: "
                                    "%s", filename, line, e)
                            else:
                                logger.warning(
                                    "Skipping PKCS#7 in %s at line %s: %s",
                                    filename, line, e)
                            continue
                        else:
                            extracted_certs.extend(certs)
                            loaded = True
                            continue

                    if label in (b'PRIVATE KEY', b'ENCRYPTED PRIVATE KEY',
                                 b'RSA PRIVATE KEY', b'DSA PRIVATE KEY',
                                 b'EC PRIVATE KEY'):
                        if not import_keys:
                            continue

                        if key_file:
                            raise RuntimeError(
                                "Can't load private key from both %s and %s" %
                                (key_file, filename))

                        # the args -v2 aes256 -v2prf hmacWithSHA256 are needed
                        # on OpenSSL 1.0.2 (fips mode). As soon as FreeIPA
                        # requires OpenSSL 1.1.0 we'll be able to drop them
                        args = [
                            paths.OPENSSL,
                            'pkcs8',
                            '-topk8',
                            '-v2',
                            'aes256',
                            '-v2prf',
                            'hmacWithSHA256',
                            '-passout',
                            'file:' + self.pwd_file,
                        ]
                        if ((label != b'PRIVATE KEY' and key_password)
                                or label == b'ENCRYPTED PRIVATE KEY'):
                            key_pwdfile = ipautil.write_tmp_file(key_password)
                            args += [
                                '-passin',
                                'file:' + key_pwdfile.name,
                            ]
                        try:
                            result = ipautil.run(args,
                                                 stdin=body,
                                                 capture_output=True)
                        except ipautil.CalledProcessError as e:
                            logger.warning(
                                "Skipping private key in %s at line %s: %s",
                                filename, line, e)
                            continue
                        else:
                            extracted_key = result.raw_output
                            key_file = filename
                            loaded = True
                            continue
                if loaded:
                    continue
                raise RuntimeError("Failed to load %s" % filename)

            # Try to load the file as DER certificate
            try:
                cert = x509.load_der_x509_certificate(data)
            except ValueError:
                pass
            else:
                extracted_certs.append(cert)
                continue

            # Try to import the file as PKCS#12 file
            if import_keys:
                try:
                    self.import_pkcs12(filename, key_password)
                except Pkcs12ImportUnknownError:
                    # the file may not be a PKCS#12 file,
                    # go to the generic error about unrecognized format
                    pass
                except RuntimeError as e:
                    raise RuntimeError("Failed to load %s: %s" %
                                       (filename, str(e)))
                else:
                    if key_file:
                        raise RuntimeError(
                            "Can't load private key from both %s and %s" %
                            (key_file, filename))
                    key_file = filename

                    server_certs = self.find_server_certs()
                    if key_nickname:
                        for nickname, _trust_flags in server_certs:
                            if nickname == key_nickname:
                                break
                        else:
                            raise RuntimeError(
                                "Server certificate \"%s\" not found in %s" %
                                (key_nickname, filename))
                    else:
                        if len(server_certs) > 1:
                            raise RuntimeError(
                                "%s server certificates found in %s, "
                                "expecting only one" %
                                (len(server_certs), filename))

                    continue

            # Supported formats were tried but none succeeded
            raise RuntimeError("Failed to load %s: unrecognized format" %
                               filename)

        if import_keys and not key_file:
            raise RuntimeError("No server certificates found in %s" %
                               (', '.join(files)))

        for cert in extracted_certs:
            nickname = str(DN(cert.subject))
            self.add_cert(cert, nickname, EMPTY_TRUST_FLAGS)

        if extracted_key:
            with tempfile.NamedTemporaryFile() as in_file, \
                    tempfile.NamedTemporaryFile() as out_file:
                for cert in extracted_certs:
                    in_file.write(cert.public_bytes(x509.Encoding.PEM))
                in_file.write(extracted_key)
                in_file.flush()
                out_password = ipautil.ipa_generate_password()
                out_pwdfile = ipautil.write_tmp_file(out_password)
                args = [
                    paths.OPENSSL,
                    'pkcs12',
                    '-export',
                    '-in',
                    in_file.name,
                    '-out',
                    out_file.name,
                    '-passin',
                    'file:' + self.pwd_file,
                    '-passout',
                    'file:' + out_pwdfile.name,
                    '-certpbe',
                    'aes-128-cbc',
                    '-keypbe',
                    'aes-128-cbc',
                ]
                try:
                    ipautil.run(args)
                except ipautil.CalledProcessError as e:
                    raise RuntimeError(
                        "No matching certificate found for private key from "
                        "%s" % key_file)

                self.import_pkcs12(out_file.name, out_password)
Example #32
0
def load_pkcs12(cert_files,
                key_password,
                key_nickname,
                ca_cert_files,
                host_name=None,
                realm_name=None):
    """
    Load and verify server certificate and private key from multiple files

    The files are accepted in PEM and DER certificate, PKCS#7 certificate
    chain, PKCS#8 and raw private key and PKCS#12 formats.

    :param cert_files: Names of server certificate and private key files to
        import
    :param key_password: Password to decrypt private keys
    :param key_nickname: Nickname of the private key to import from PKCS#12
        files
    :param ca_cert_files: Names of CA certificate files to import
    :param host_name: Host name of the server
    :returns: Temporary PKCS#12 file with the server certificate, private key
        and CA certificate chain, password to unlock the PKCS#12 file and
        the CA certificate of the CA that issued the server certificate
    """
    with certs.NSSDatabase() as nssdb:
        nssdb.create_db()

        try:
            nssdb.import_files(cert_files, True, key_password, key_nickname)
        except RuntimeError as e:
            raise ScriptError(str(e))

        if ca_cert_files:
            try:
                nssdb.import_files(ca_cert_files)
            except RuntimeError as e:
                raise ScriptError(str(e))

        for nickname, trust_flags in nssdb.list_certs():
            if trust_flags.has_key:
                key_nickname = nickname
                continue
            nssdb.trust_root_cert(nickname, EXTERNAL_CA_TRUST_FLAGS)

        # Check we have the whole cert chain & the CA is in it
        trust_chain = list(reversed(nssdb.get_trust_chain(key_nickname)))
        ca_cert = None
        for nickname in trust_chain[1:]:
            cert = nssdb.get_cert(nickname)
            if ca_cert is None:
                ca_cert = cert

            subject = DN(cert.subject)
            issuer = DN(cert.issuer)

            if subject == issuer:
                break
        else:
            raise ScriptError(
                "The full certificate chain is not present in %s" %
                (", ".join(cert_files)))

        # verify CA validity and pathlen. The trust_chain list is in reverse
        # order. trust_chain[1] is the first intermediate CA cert and must
        # have pathlen >= 0.
        for minpathlen, nickname in enumerate(trust_chain[1:], start=0):
            try:
                nssdb.verify_ca_cert_validity(nickname, minpathlen)
            except ValueError as e:
                raise ScriptError("CA certificate %s in %s is not valid: %s" %
                                  (subject, ", ".join(cert_files), e))

        if host_name is not None:
            try:
                nssdb.verify_server_cert_validity(key_nickname, host_name)
            except ValueError as e:
                raise ScriptError(
                    "The server certificate in %s is not valid: %s" %
                    (", ".join(cert_files), e))

        if realm_name is not None:
            try:
                nssdb.verify_kdc_cert_validity(key_nickname, realm_name)
            except ValueError as e:
                raise ScriptError(
                    "The KDC certificate in %s is not valid: %s" %
                    (", ".join(cert_files), e))

        out_file = tempfile.NamedTemporaryFile()
        out_password = ipautil.ipa_generate_password()
        out_pwdfile = ipautil.write_tmp_file(out_password)
        args = [
            paths.PK12UTIL,
            '-o',
            out_file.name,
            '-n',
            key_nickname,
            '-d',
            nssdb.secdir,
            '-k',
            nssdb.pwd_file,
            '-w',
            out_pwdfile.name,
        ]
        ipautil.run(args)

    return out_file, out_password, ca_cert
Example #33
0
def install_pem_from_p12(p12_fname, p12_passwd, pem_fname):
    pwd = ipautil.write_tmp_file(p12_passwd)
    ipautil.run([
        paths.OPENSSL, "pkcs12", "-nokeys", "-clcerts", "-in", p12_fname,
        "-out", pem_fname, "-passin", "file:" + pwd.name
    ])
Example #34
0
    def import_files(self, files, import_keys=False, key_password=None,
                     key_nickname=None):
        """
        Import certificates and a single private key from multiple files

        The files may be in PEM and DER certificate, PKCS#7 certificate chain,
        PKCS#8 and raw private key and PKCS#12 formats.

        :param files: Names of files to import
        :param import_keys: Whether to import private keys
        :param key_password: Password to decrypt private keys
        :param key_nickname: Nickname of the private key to import from PKCS#12
            files
        """
        key_file = None
        extracted_key = None
        extracted_certs = []

        for filename in files:
            try:
                with open(filename, 'rb') as f:
                    data = f.read()
            except IOError as e:
                raise RuntimeError(
                    "Failed to open %s: %s" % (filename, e.strerror))

            # Try to parse the file as PEM file
            matches = list(
                re.finditer(
                    br'-----BEGIN (.+?)-----(.*?)-----END \1-----',
                    data, re.DOTALL
                )
            )
            if matches:
                loaded = False
                for match in matches:
                    body = match.group()
                    label = match.group(1)
                    line = len(data[:match.start() + 1].splitlines())

                    if label in (b'CERTIFICATE', b'X509 CERTIFICATE',
                                 b'X.509 CERTIFICATE'):
                        try:
                            cert = x509.load_pem_x509_certificate(body)
                        except ValueError as e:
                            if label != b'CERTIFICATE':
                                logger.warning(
                                    "Skipping certificate in %s at line %s: "
                                    "%s",
                                    filename, line, e)
                                continue
                        else:
                            extracted_certs.append(cert)
                            loaded = True
                            continue

                    if label in (b'PKCS7', b'PKCS #7 SIGNED DATA',
                                 b'CERTIFICATE'):
                        try:
                            certs = x509.pkcs7_to_certs(body)
                        except ipautil.CalledProcessError as e:
                            if label == b'CERTIFICATE':
                                logger.warning(
                                    "Skipping certificate in %s at line %s: "
                                    "%s",
                                    filename, line, e)
                            else:
                                logger.warning(
                                    "Skipping PKCS#7 in %s at line %s: %s",
                                    filename, line, e)
                            continue
                        else:
                            extracted_certs.extend(certs)
                            loaded = True
                            continue

                    if label in (b'PRIVATE KEY', b'ENCRYPTED PRIVATE KEY',
                                 b'RSA PRIVATE KEY', b'DSA PRIVATE KEY',
                                 b'EC PRIVATE KEY'):
                        if not import_keys:
                            continue

                        if key_file:
                            raise RuntimeError(
                                "Can't load private key from both %s and %s" %
                                (key_file, filename))

                        # the args -v2 aes256 -v2prf hmacWithSHA256 are needed
                        # on OpenSSL 1.0.2 (fips mode). As soon as FreeIPA
                        # requires OpenSSL 1.1.0 we'll be able to drop them
                        args = [
                            paths.OPENSSL, 'pkcs8',
                            '-topk8',
                            '-v2', 'aes256', '-v2prf', 'hmacWithSHA256',
                            '-passout', 'file:' + self.pwd_file,
                        ]
                        if ((label != b'PRIVATE KEY' and key_password) or
                                label == b'ENCRYPTED PRIVATE KEY'):
                            key_pwdfile = ipautil.write_tmp_file(key_password)
                            args += [
                                '-passin', 'file:' + key_pwdfile.name,
                            ]
                        try:
                            result = ipautil.run(
                                args, stdin=body, capture_output=True)
                        except ipautil.CalledProcessError as e:
                            logger.warning(
                                "Skipping private key in %s at line %s: %s",
                                filename, line, e)
                            continue
                        else:
                            extracted_key = result.raw_output
                            key_file = filename
                            loaded = True
                            continue
                if loaded:
                    continue
                raise RuntimeError("Failed to load %s" % filename)

            # Try to load the file as DER certificate
            try:
                cert = x509.load_der_x509_certificate(data)
            except ValueError:
                pass
            else:
                extracted_certs.append(cert)
                continue

            # Try to import the file as PKCS#12 file
            if import_keys:
                try:
                    self.import_pkcs12(filename, key_password)
                except RuntimeError:
                    pass
                else:
                    if key_file:
                        raise RuntimeError(
                            "Can't load private key from both %s and %s" %
                            (key_file, filename))
                    key_file = filename

                    server_certs = self.find_server_certs()
                    if key_nickname:
                        for nickname, _trust_flags in server_certs:
                            if nickname == key_nickname:
                                break
                        else:
                            raise RuntimeError(
                                "Server certificate \"%s\" not found in %s" %
                                (key_nickname, filename))
                    else:
                        if len(server_certs) > 1:
                            raise RuntimeError(
                                "%s server certificates found in %s, "
                                "expecting only one" %
                                (len(server_certs), filename))

                    continue

            raise RuntimeError("Failed to load %s" % filename)

        if import_keys and not key_file:
            raise RuntimeError(
                "No server certificates found in %s" % (', '.join(files)))

        for cert in extracted_certs:
            nickname = str(DN(cert.subject))
            self.add_cert(cert, nickname, EMPTY_TRUST_FLAGS)

        if extracted_key:
            with tempfile.NamedTemporaryFile() as in_file, \
                    tempfile.NamedTemporaryFile() as out_file:
                for cert in extracted_certs:
                    in_file.write(cert.public_bytes(x509.Encoding.PEM))
                in_file.write(extracted_key)
                in_file.flush()
                out_password = ipautil.ipa_generate_password()
                out_pwdfile = ipautil.write_tmp_file(out_password)
                args = [
                    paths.OPENSSL, 'pkcs12',
                    '-export',
                    '-in', in_file.name,
                    '-out', out_file.name,
                    '-passin', 'file:' + self.pwd_file,
                    '-passout', 'file:' + out_pwdfile.name,
                ]
                try:
                    ipautil.run(args)
                except ipautil.CalledProcessError as e:
                    raise RuntimeError(
                        "No matching certificate found for private key from "
                        "%s" % key_file)

                self.import_pkcs12(out_file.name, out_password)
Example #35
0
    def execute(self, ldapuri, bindpw, **options):
        ldap = self.api.Backend.ldap2
        self.normalize_options(options)
        config = ldap.get_ipa_config()

        ds_base_dn = options.get('basedn')
        if ds_base_dn is not None:
            assert isinstance(ds_base_dn, DN)

        # check if migration mode is enabled
        if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE':
            return dict(result={}, failed={}, enabled=False, compat=True)

        # connect to DS
        cacert = None
        if options.get('cacertfile') is not None:
            # store CA cert into file
            tmp_ca_cert_f = write_tmp_file(options['cacertfile'])
            cacert = tmp_ca_cert_f.name

            # start TLS connection
            ds_ldap = LDAPClient(ldapuri, cacert=cacert)
            ds_ldap.simple_bind(options['binddn'], bindpw)

            tmp_ca_cert_f.close()
        else:
            ds_ldap = LDAPClient(ldapuri, cacert=cacert)
            ds_ldap.simple_bind(options['binddn'], bindpw)

        # check whether the compat plugin is enabled
        if not options.get('compat'):
            try:
                ldap.get_entry(DN(('cn', 'compat'), (api.env.basedn)))
                return dict(result={}, failed={}, enabled=True, compat=False)
            except errors.NotFound:
                pass

        if not ds_base_dn:
            # retrieve base DN from remote LDAP server
            entries, _truncated = ds_ldap.find_entries(
                '',
                ['namingcontexts', 'defaultnamingcontext'],
                DN(''),
                ds_ldap.SCOPE_BASE,
                size_limit=-1,
                time_limit=0,
            )
            if 'defaultnamingcontext' in entries[0]:
                ds_base_dn = DN(entries[0]['defaultnamingcontext'][0])
                assert isinstance(ds_base_dn, DN)
            else:
                try:
                    ds_base_dn = DN(entries[0]['namingcontexts'][0])
                    assert isinstance(ds_base_dn, DN)
                except (IndexError, KeyError) as e:
                    raise Exception(str(e))

        # migrate!
        (migrated, failed) = self.migrate(ldap, config, ds_ldap, ds_base_dn,
                                          options)

        return dict(result=migrated, failed=failed, enabled=True, compat=True)
Example #36
0
    def renew_external_step_2(self, ca, old_cert_der):
        print("Importing the renewed CA certificate, please wait")

        options = self.options
        conn = api.Backend.ldap2
        cert_file, ca_file = installutils.load_external_cert(
            options.external_cert_files, x509.subject_base())

        old_cert_obj = x509.load_certificate(old_cert_der, x509.DER)
        old_der_subject = x509.get_der_subject(old_cert_der, x509.DER)
        old_spki = old_cert_obj.public_key().public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.SubjectPublicKeyInfo)

        with open(cert_file.name) as f:
            new_cert_data = f.read()
        new_cert_der = x509.normalize_certificate(new_cert_data)
        new_cert_obj = x509.load_certificate(new_cert_der, x509.DER)
        new_der_subject = x509.get_der_subject(new_cert_der, x509.DER)
        new_spki = new_cert_obj.public_key().public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.SubjectPublicKeyInfo)

        if new_cert_obj.subject != old_cert_obj.subject:
            raise admintool.ScriptError(
                "Subject name mismatch (visit "
                "http://www.freeipa.org/page/Troubleshooting for "
                "troubleshooting guide)")
        if new_der_subject != old_der_subject:
            raise admintool.ScriptError(
                "Subject name encoding mismatch (visit "
                "http://www.freeipa.org/page/Troubleshooting for "
                "troubleshooting guide)")
        if new_spki != old_spki:
            raise admintool.ScriptError(
                "Subject public key info mismatch (visit "
                "http://www.freeipa.org/page/Troubleshooting for "
                "troubleshooting guide)")

        with certs.NSSDatabase() as tmpdb:
            pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
            tmpdb.create_db(pw.name)
            tmpdb.add_cert(old_cert_der, 'IPA CA', 'C,,')

            try:
                tmpdb.add_cert(new_cert_der, 'IPA CA', 'C,,')
            except ipautil.CalledProcessError as e:
                raise admintool.ScriptError(
                    "Not compatible with the current CA certificate: %s" % e)

            ca_certs = x509.load_certificate_list_from_file(ca_file.name)
            for ca_cert in ca_certs:
                data = ca_cert.public_bytes(serialization.Encoding.DER)
                tmpdb.add_cert(data, str(DN(ca_cert.subject)), 'C,,')

            try:
                tmpdb.verify_ca_cert_validity('IPA CA')
            except ValueError as e:
                raise admintool.ScriptError(
                    "Not a valid CA certificate: %s (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)" % e)

            trust_chain = tmpdb.get_trust_chain('IPA CA')[:-1]
            for nickname in trust_chain:
                try:
                    ca_cert = tmpdb.get_cert(nickname)
                except RuntimeError:
                    break
                certstore.put_ca_cert_nss(conn, api.env.basedn, ca_cert,
                                          nickname, ',,')

        dn = DN(('cn', self.cert_nickname), ('cn', 'ca_renewal'),
                ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
        try:
            entry = conn.get_entry(dn, ['usercertificate'])
            entry['usercertificate'] = [new_cert_der]
            conn.update_entry(entry)
        except errors.NotFound:
            entry = conn.make_entry(
                dn,
                objectclass=['top', 'pkiuser', 'nscontainer'],
                cn=[self.cert_nickname],
                usercertificate=[new_cert_der])
            conn.add_entry(entry)
        except errors.EmptyModlist:
            pass

        try:
            ca.set_renewal_master()
        except errors.NotFound:
            raise admintool.ScriptError("CA renewal master not found")

        self.resubmit_request(ca, 'ipaRetrieval')

        print("CA certificate successfully renewed")
Example #37
0
    def renew_external_step_2(self, ca, old_cert):
        print("Importing the renewed CA certificate, please wait")

        options = self.options
        conn = api.Backend.ldap2
        cert_file, ca_file = installutils.load_external_cert(
            options.external_cert_files, x509.subject_base())

        nss_cert = None
        nss.nss_init(paths.PKI_TOMCAT_ALIAS_DIR)
        try:
            nss_cert = x509.load_certificate(old_cert, x509.DER)
            subject = nss_cert.subject
            der_subject = x509.get_der_subject(old_cert, x509.DER)
            #pylint: disable=E1101
            pkinfo = nss_cert.subject_public_key_info.format()
            #pylint: enable=E1101

            nss_cert = x509.load_certificate_from_file(cert_file.name)
            cert = nss_cert.der_data
            if nss_cert.subject != subject:
                raise admintool.ScriptError(
                    "Subject name mismatch (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)")
            if x509.get_der_subject(cert, x509.DER) != der_subject:
                raise admintool.ScriptError(
                    "Subject name encoding mismatch (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)")
            #pylint: disable=E1101
            if nss_cert.subject_public_key_info.format() != pkinfo:
                raise admintool.ScriptError(
                    "Subject public key info mismatch (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)")
            #pylint: enable=E1101
        finally:
            del nss_cert
            nss.nss_shutdown()

        with certs.NSSDatabase() as tmpdb:
            pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
            tmpdb.create_db(pw.name)
            tmpdb.add_cert(old_cert, 'IPA CA', 'C,,')

            try:
                tmpdb.add_cert(cert, 'IPA CA', 'C,,')
            except ipautil.CalledProcessError as e:
                raise admintool.ScriptError(
                    "Not compatible with the current CA certificate: %s" % e)

            ca_certs = x509.load_certificate_list_from_file(ca_file.name)
            for ca_cert in ca_certs:
                tmpdb.add_cert(ca_cert.der_data, str(ca_cert.subject), 'C,,')
            del ca_certs
            del ca_cert

            try:
                tmpdb.verify_ca_cert_validity('IPA CA')
            except ValueError as e:
                raise admintool.ScriptError(
                    "Not a valid CA certificate: %s (visit "
                    "http://www.freeipa.org/page/Troubleshooting for "
                    "troubleshooting guide)" % e)

            trust_chain = tmpdb.get_trust_chain('IPA CA')[:-1]
            for nickname in trust_chain:
                try:
                    ca_cert = tmpdb.get_cert(nickname)
                except RuntimeError:
                    break
                certstore.put_ca_cert_nss(
                    conn, api.env.basedn, ca_cert, nickname, ',,')

        dn = DN(('cn', self.cert_nickname), ('cn', 'ca_renewal'),
                ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
        try:
            entry = conn.get_entry(dn, ['usercertificate'])
            entry['usercertificate'] = [cert]
            conn.update_entry(entry)
        except errors.NotFound:
            entry = conn.make_entry(
                dn,
                objectclass=['top', 'pkiuser', 'nscontainer'],
                cn=[self.cert_nickname],
                usercertificate=[cert])
            conn.add_entry(entry)
        except errors.EmptyModlist:
            pass

        try:
            ca.set_renewal_master()
        except errors.NotFound:
            raise admintool.ScriptError("CA renewal master not found")

        self.resubmit_request(ca, 'ipaRetrieval')

        print("CA certificate successfully renewed")