Exemple #1
0
def verify_kdc_cert_validity(kdc_cert, ca_certs, realm):
    with NamedTemporaryFile() as kdc_file, NamedTemporaryFile() as ca_file:
        kdc_file.write(kdc_cert.public_bytes(x509.Encoding.PEM))
        kdc_file.flush()
        x509.write_certificate_list(ca_certs, ca_file.name)
        ca_file.flush()

        try:
            ipautil.run([
                paths.OPENSSL, 'verify', '-CAfile', ca_file.name, kdc_file.name
            ],
                        capture_output=True)
        except ipautil.CalledProcessError as e:
            raise ValueError(e.output)

        try:
            eku = kdc_cert.extensions.get_extension_for_class(
                cryptography.x509.ExtendedKeyUsage)
            list(eku.value).index(
                cryptography.x509.ObjectIdentifier(x509.EKU_PKINIT_KDC))
        except (cryptography.x509.ExtensionNotFound, ValueError):
            raise ValueError("invalid for a KDC")

        principal = str(Principal(['krbtgt', realm], realm))
        gns = x509.process_othernames(kdc_cert.san_general_names)
        for gn in gns:
            if isinstance(gn, x509.KRB5PrincipalName) and gn.name == principal:
                break
        else:
            raise ValueError("invalid for realm %s" % realm)
Exemple #2
0
def verify_kdc_cert_validity(kdc_cert, ca_certs, realm):
    with NamedTemporaryFile() as kdc_file, NamedTemporaryFile() as ca_file:
        kdc_file.write(kdc_cert.public_bytes(x509.Encoding.PEM))
        kdc_file.flush()
        x509.write_certificate_list(ca_certs, ca_file.name)
        ca_file.flush()

        try:
            ipautil.run(
                [paths.OPENSSL, 'verify', '-CAfile', ca_file.name,
                 kdc_file.name],
                capture_output=True)
        except ipautil.CalledProcessError as e:
            raise ValueError(e.output)

        try:
            eku = kdc_cert.extensions.get_extension_for_class(
                cryptography.x509.ExtendedKeyUsage)
            list(eku.value).index(
                cryptography.x509.ObjectIdentifier(x509.EKU_PKINIT_KDC))
        except (cryptography.x509.ExtensionNotFound,
                ValueError):
            raise ValueError("invalid for a KDC")

        principal = str(Principal(['krbtgt', realm], realm))
        gns = x509.process_othernames(kdc_cert.san_general_names)
        for gn in gns:
            if isinstance(gn, x509.KRB5PrincipalName) and gn.name == principal:
                break
        else:
            raise ValueError("invalid for realm %s" % realm)
Exemple #3
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))

                        args = [
                            OPENSSL,
                            'pkcs8',
                            '-topk8',
                            '-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(), tempfile.NamedTemporaryFile() \
                    as (in_file, out_file):
                x509.write_certificate_list(extracted_certs, in_file.name)
                in_file.write(extracted_key)
                in_file.flush()
                out_password = ipautil.ipa_generate_password()
                out_pwdfile = ipautil.write_tmp_file(out_password)
                args = [
                    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)
Exemple #4
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))

                        args = [
                            OPENSSL, 'pkcs8',
                            '-topk8',
                            '-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(), tempfile.NamedTemporaryFile() \
                    as (in_file, out_file):
                x509.write_certificate_list(extracted_certs, in_file.name)
                in_file.write(extracted_key)
                in_file.flush()
                out_password = ipautil.ipa_generate_password()
                out_pwdfile = ipautil.write_tmp_file(out_password)
                args = [
                    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)