Beispiel #1
0
    def _validate_cert(self, ocsp_staple=None):
        """
        Validates the certificate and its chain, including the OCSP staple if
        there is one in :attr:`self.ocsp_staple`.

        :param asn1crypto.core.Sequence ocsp_staple: Binary ocsp staple data.
        :return array: Validated certificate chain.
        :raises CertValidationError: If there is any problem with the
            certificate chain and/or the staple, e.g. certificate is revoked,
            chain is incomplete or invalid (i.e. wrong intermediate with
            server certificate), certificate is simply invalid, etc.

        .. Note:: At this point it becomes known what the role of the
            certiticates in the chain is. With the exception of the root, which
            is usually not kept with the intermediates and the certificate
            because ever client has its own copy of it.
        """
        try:
            if ocsp_staple is None:
                LOG.info("Validating without OCSP staple.")
                context = certvalidator.ValidationContext()
            else:
                LOG.info("Validating with OCSP staple.")
                context = certvalidator.ValidationContext(
                    ocsps=[ocsp_staple.data], allow_fetching=False)
            validator = certvalidator.CertificateValidator(
                self.end_entity,
                self.intermediates,
                validation_context=context)
            chain = validator.validate_usage(
                key_usage=set(['digital_signature']),
                extended_key_usage=set(['server_auth']),
                extended_optional=True)
            LOG.info("Certificate chain for \"%s\" validated.", self.filename)
            return chain
        except certvalidator.errors.RevokedError:
            raise CertValidationError(
                "Certificate \"{}\" was revoked, will not try to parse it "
                "again.".format(self.filename))
        except certvalidator.errors.InvalidCertificateError:
            raise CertValidationError(
                "Certificate \"{}\" is invalid, will not try to parse it "
                "again.".format(self.filename))
        except (certvalidator.errors.PathBuildingError,
                certvalidator.errors.PathValidationError):
            raise CertValidationError(
                "Failed to validate certificate path for \"{}\", will not "
                "try to parse it again.".format(self.filename))
Beispiel #2
0
def test_common_name_selection(hostnames, common_name):
    cert, pkey = WebhookServer.build_certificate(hostnames)
    context = certvalidator.ValidationContext(extra_trust_roots=[cert])
    validator = certvalidator.CertificateValidator(cert,
                                                   validation_context=context)
    path = validator.validate_tls(common_name)
    assert path.first.subject.native['common_name'] == common_name
Beispiel #3
0
    async def guess_host() -> Optional[str]:
        try:
            import certvalidator
        except ImportError:
            raise MissingDependencyError(
                "Auto-guessing cluster types requires an extra dependency: "
                "run `pip install certvalidator` or `pip install kopf[dev]`. "
                "More: https://kopf.readthedocs.io/en/stable/admission/")

        hostname, cert = await scanning.read_sslcert()
        valcontext = certvalidator.ValidationContext(extra_trust_roots=[cert])
        validator = certvalidator.CertificateValidator(
            cert, validation_context=valcontext)
        certpath = validator.validate_tls(hostname)
        issuer_cn = certpath.first.issuer.native.get('common_name', '')
        subject_cn = certpath.first.subject.native.get('common_name', '')
        subject_org = certpath.first.subject.native.get(
            'organization_name', '')

        if subject_cn == 'k3s' or subject_org == 'k3s' or issuer_cn.startswith(
                'k3s-'):
            return WebhookK3dServer.DEFAULT_HOST
        elif subject_cn == 'minikube' or issuer_cn == 'minikubeCA':
            return WebhookMinikubeServer.DEFAULT_HOST
        else:
            versioninfo = await scanning.read_version()
            if '+k3s' in versioninfo.get('gitVersion', ''):
                return WebhookK3dServer.DEFAULT_HOST
        return None
Beispiel #4
0
    async def guess_host() -> Optional[str]:
        try:
            import certvalidator
        except ImportError:
            raise MissingDependencyError(
                "Auto-guessing cluster types requires an extra dependency: "
                "run `pip install certvalidator` or `pip install kopf[dev]`. "
                "More: https://kopf.readthedocs.io/en/stable/admission/")

        hostname, cert = await api.read_sslcert()
        valcontext = certvalidator.ValidationContext(extra_trust_roots=[cert])
        validator = certvalidator.CertificateValidator(cert, validation_context=valcontext)
        certpath = validator.validate_tls(hostname)
        issuer_cn = certpath.first.issuer.native.get('common_name', '')
        subject_cn = certpath.first.subject.native.get('common_name', '')
        subject_org = certpath.first.subject.native.get('organization_name', '')

        if subject_cn == 'k3s' or subject_org == 'k3s' or issuer_cn.startswith('k3s-'):
            return WebhookK3dServer.DEFAULT_HOST
        elif subject_cn == 'minikube' or issuer_cn == 'minikubeCA':
            return WebhookMinikubeServer.DEFAULT_HOST
        else:
            # The default timeouts & backoffs are used to retrieve the cluster
            # version, not those from the operator. It is too difficult to get
            # the settings here in webhooks. The "proper" way is to retrieve
            # the version in observation routines and pass it via contextvars,
            # but this is too overcomplicated for a dev-mode helping utility.
            settings = configuration.OperatorSettings()
            versioninfo = await scanning.read_version(settings=settings, logger=logger)
            if '+k3s' in versioninfo.get('gitVersion', ''):
                return WebhookK3dServer.DEFAULT_HOST
        return None
Beispiel #5
0
def test_certificate_generation():
    names = ['hostname1', 'hostname2', '1.2.3.4', '0:0:0:0:0:0:0:1']
    cert, pkey = WebhookServer.build_certificate(names)
    context = certvalidator.ValidationContext(extra_trust_roots=[cert])
    validator = certvalidator.CertificateValidator(cert, validation_context=context)
    path = validator.validate_tls('hostname1')
    assert len(path) == 1  # self-signed
    assert path.first.ca
    assert path.first.self_issued
    assert set(path.first.valid_domains) == {'hostname1', 'hostname2', '1.2.3.4', '::1'}
    assert set(path.first.valid_ips) == {'1.2.3.4', '::1'}