Exemplo n.º 1
0
def public_key(csr=None, allowed_keys=None, **kwargs):
    """Ensure the public key has the known type and size.

    Configuration provides a dictionary of key types and minimum sizes.
    """
    if allowed_keys is None or not isinstance(allowed_keys, dict):
        raise v_errors.ValidationError("Allowed keys configuration missing")

    algo = csr.get_public_key_algo()
    algo_names = {
        rfc2437.rsaEncryption: 'RSA',
        rfc2459.id_dsa: 'DSA',
        }
    algo_name = algo_names.get(algo)
    if algo_name is None:
        raise v_errors.ValidationError("Unknown public key type")

    min_size = allowed_keys.get(algo_name)
    if min_size is None:
        raise v_errors.ValidationError(
            "Key type not allowed (%s)" % (algo_name,))
    if min_size == 0:
        # key size is not enforced
        return

    if csr.get_public_key_size() < min_size:
        raise v_errors.ValidationError("Key size too small")
Exemplo n.º 2
0
def common_name(csr, allowed_domains=[], allowed_networks=[], **kwargs):
    """Check the CN entry is a known domain.

    Refuse requests for certificates if they contain multiple CN
    entries, or the domain does not match the list of known suffixes.
    """
    alt_present = any(ext.get_name() == "subjectAltName"
                      for ext in csr.get_extensions())

    CNs = csr.get_subject().get_entries_by_oid(x509_name.OID_commonName)

    if len(CNs) > 1:
        raise v_errors.ValidationError("Too many CNs in the request")

    # rfc2459#section-4.2.1.6 says so
    if len(CNs) == 0 and not alt_present:
        raise v_errors.ValidationError("Alt subjects have to exist if the main"
                                       " subject doesn't")

    if len(CNs) > 0:
        cn = utils.csr_require_cn(csr)
        try:
            # is it an IP rather than domain?
            ip = netaddr.IPAddress(cn)
            if not (utils.check_networks(ip, allowed_networks)):
                raise v_errors.ValidationError(
                    "Address '%s' not allowed (does not match known networks)"
                    % cn)
        except netaddr.AddrFormatError:
            if not (utils.check_domains(cn, allowed_domains)):
                raise v_errors.ValidationError(
                    "Domain '%s' not allowed (does not match known domains)"
                    % cn)
Exemplo n.º 3
0
def csr_require_cn(csr):
    cns = csr.get_subject_cn()
    if not cns:
        raise errors.ValidationError("CSR is lacking a CN in the Subject")
    if len(cns) > 1:
        raise errors.ValidationError("CSR has too many CN entries")
    return cns[0]
Exemplo n.º 4
0
def _csr_signature(csr):
    """Ensure that the CSR has a valid self-signature."""
    try:
        if not csr.verify():
            raise errors.ValidationError("Signature on the CSR is not valid")
    except x509_errors.X509Error:
        raise errors.ValidationError("Signature on the CSR is not valid")
Exemplo n.º 5
0
def ext_key_usage(csr=None, allowed_usage=None, **kwargs):
    """Ensure only accepted extended key usages are specified."""

    # transform all possible names into oids we actually check
    for i, usage in enumerate(allowed_usage):
        if usage in extension.EXT_KEY_USAGE_NAMES_INV:
            allowed_usage[i] = extension.EXT_KEY_USAGE_NAMES_INV[usage]
        elif usage in extension.EXT_KEY_USAGE_SHORT_NAMES_INV:
            allowed_usage[i] = extension.EXT_KEY_USAGE_SHORT_NAMES_INV[usage]
        else:
            try:
                oid = pyasn1_univ.ObjectIdentifier(usage)
                allowed_usage[i] = oid
            except Exception:
                raise v_errors.ValidationError("Unknown usage: %s" % (usage,))

    allowed = set(allowed_usage)
    denied = set()

    for ext in csr.get_extensions(extension.X509ExtensionExtendedKeyUsage):
        usages = set(ext.get_all_usages())
        denied = denied | (usages - allowed)
    if denied:
        text_denied = [extension.EXT_KEY_USAGE_SHORT_NAMES.get(x)
                       for x in denied]
        raise v_errors.ValidationError("Found some prohibited key usages: %s"
                                       % ', '.join(text_denied))
Exemplo n.º 6
0
def csr_signature(csr=None, **kwargs):
    """Ensure that the CSR has a valid self-signature."""
    try:
        if not csr.verify():
            raise v_errors.ValidationError("Signature on the CSR is not valid")
    except errors.X509Error:
        raise v_errors.ValidationError("Signature on the CSR is not valid")
Exemplo n.º 7
0
def source_cidrs(request=None, cidrs=None, **kwargs):
    """Ensure that the request comes from a known source."""
    for cidr in cidrs:
        try:
            r = netaddr.IPNetwork(cidr)
            if request.client_addr in r:
                return
        except netaddr.AddrFormatError:
            raise v_errors.ValidationError(
                "Cidr '%s' does not describe a valid network" % cidr)
    raise v_errors.ValidationError(
        "No network matched the request source '%s'" % request.client_addr)
Exemplo n.º 8
0
def _csr_signature(csr):
    """Ensure that the CSR has a valid self-signature."""
    # first check for deprecated signatures - verification on those will fail
    algo = csr.uses_deprecated_algorithm()
    if algo:
        raise errors.ValidationError("CSR rejected for using a known broken, "
                                     "or deprecated algorithm: %s" % algo)

    try:
        if not csr.verify():
            raise errors.ValidationError("Signature on the CSR is not valid")
    except x509_errors.X509Error:
        raise errors.ValidationError("Signature on the CSR is not valid")
Exemplo n.º 9
0
def _critical_flags(csr):
    """Various rules define whether critical flag is required."""
    for ext in csr.get_extensions():
        if isinstance(ext, extension.X509ExtensionSubjectAltName):
            if len(csr.get_subject()) == 0 and not ext.get_critical():
                raise errors.ValidationError(
                    "SAN must be critical if subject is empty "
                    "(RFC5280/4.1.2.6)")
        if isinstance(ext, extension.X509ExtensionBasicConstraints):
            if not ext.get_critical():
                raise errors.ValidationError(
                    "Basic constraints has to be marked critical "
                    "(RFC5280/4.1.2.9)")
Exemplo n.º 10
0
def whitelist_names(csr=None, names=[], allow_cn_id=False, allow_dns_id=False,
                    allow_ip_id=False, allow_wildcard=False, **kwargs):
    """Ensure names match the whitelist in the allowed name slots."""

    allowed_domains, allowed_ips, allowed_ranges = _split_names_by_type(names)

    for dns_id in csr.get_subject_dns_ids():
        if not allow_dns_id:
            raise v_errors.ValidationError("IP-ID not allowed")
        valid = False
        for allowed_domain in allowed_domains:
            if utils.compare_name_pattern(dns_id, allowed_domain,
                                          allow_wildcard):
                valid = True
                break
        if not valid:
            raise v_errors.ValidationError(
                "Value `%s` not allowed in DNS-ID" % (dns_id,))

    for ip_id in csr.get_subject_ip_ids():
        if not allow_ip_id:
            raise v_errors.ValidationError("IP-ID not allowed")
        if ip_id in allowed_ips:
            continue
        for net in allowed_ranges:
            if ip_id in net:
                continue
        raise v_errors.ValidationError(
            "Value `%s` not allowed in IP-ID" % (ip_id,))

    for cn_id in csr.get_subject_cn():
        if not allow_cn_id:
            raise v_errors.ValidationError("CN-ID not allowed")
        ip = utils.maybe_ip(cn_id)
        if ip:
            # current CN is an ip address
            if ip in allowed_ips:
                continue
            if any((ip in net) for net in allowed_ranges):
                continue
            raise v_errors.ValidationError(
                "Value `%s` not allowed in CN-ID" % (cn_id,))
        else:
            # current CN is a domain
            valid = False
            for allowed_domain in allowed_domains:
                if utils.compare_name_pattern(cn_id, allowed_domain,
                                              allow_wildcard):
                    valid = True
                    break
            if valid:
                continue
            raise v_errors.ValidationError(
                "Value `%s` not allowed in CN-ID" % (cn_id,))

    if csr.has_unknown_san_entries():
        raise v_errors.ValidationError("Request contains unknown SAN entries")
Exemplo n.º 11
0
def extensions(csr=None, allowed_extensions=[], **kwargs):
    """Ensure only accepted extensions are used."""
    exts = csr.get_extensions() or []
    for ext in exts:
        if (ext.get_name() not in allowed_extensions and
                str(ext.get_oid()) not in allowed_extensions):
            raise v_errors.ValidationError("Extension '%s' not allowed"
                                           % ext.get_name())
Exemplo n.º 12
0
def alternative_names_ip(csr, allowed_domains=[], allowed_networks=[],
                         **kwargs):
    """Check known domain and ip alternative names.

    Refuse requests for certificates if the domain does not match
    the list of known suffixes, or network ranges.
    """

    for name_type, name in utils.iter_alternative_names(csr,
                                                        ['DNS', 'IP Address']):
        if name_type == 'DNS' and not utils.check_domains(name,
                                                          allowed_domains):
            raise v_errors.ValidationError("Domain '%s' not allowed (doesn't"
                                           " match known domains)" % name)
        if name_type == 'IP Address':
            if not utils.check_networks(name, allowed_networks):
                raise v_errors.ValidationError("IP '%s' not allowed (doesn't"
                                               " match known networks)" % name)
Exemplo n.º 13
0
def alternative_names(csr, allowed_domains=[], **kwargs):
    """Check known domain alternative names.

    Refuse requests for certificates if the domain does not match
    the list of known suffixes, or network ranges.
    """

    for _, name in utils.iter_alternative_names(csr, ['DNS']):
        if not utils.check_domains(name, allowed_domains):
            raise v_errors.ValidationError("Domain '%s' not allowed (doesn't"
                                           " match known domains)" % name)
Exemplo n.º 14
0
def blacklist_names(csr, domains=[], **kwargs):
    """Check for blacklisted names in CN and altNames."""

    if not domains:
        logger.warning("No domains were configured for the blacklist filter, "
                       "consider disabling the step or providing a list")
        return

    CNs = csr.get_subject().get_entries_by_oid(x509_name.OID_commonName)
    if len(CNs) > 0:
        cn = utils.csr_require_cn(csr)
        if utils.check_domains(cn, domains):
            raise v_errors.ValidationError("Domain '%s' not allowed "
                                           "(CN blacklisted)" % cn)

    for _, name in utils.iter_alternative_names(csr, ['DNS'],
                                                fail_other_types=False):
        if utils.check_domains(name, domains):
            raise v_errors.ValidationError("Domain '%s' not allowed "
                                           "(alt blacklisted)" % name)
Exemplo n.º 15
0
def _no_extension_duplicates(csr):
    """Only one extension with a given oid is allowed.

    See RFC5280 section 4.2
    """
    seen_oids = set()
    for ext in csr.get_extensions():
        oid = ext.get_oid()
        if oid in seen_oids:
            raise errors.ValidationError(
                "Duplicate extension with oid %s (RFC5280/4.2)" % oid)
        seen_oids.add(oid)
Exemplo n.º 16
0
def key_usage(csr=None, allowed_usage=None, **kwargs):
    """Ensure only accepted key usages are specified."""
    allowed = set(extension.LONG_KEY_USAGE_NAMES.get(x, x) for x in
                  allowed_usage)
    denied = set()

    for ext in (csr.get_extensions() or []):
        if isinstance(ext, extension.X509ExtensionKeyUsage):
            usages = set(ext.get_all_usages())
            denied = denied | (usages - allowed)
    if denied:
        raise v_errors.ValidationError("Found some prohibited key usages: %s"
                                       % ', '.join(denied))
Exemplo n.º 17
0
def _valid_domains(csr):
    """Format of the domin names

    See RFC5280 section 4.2.1.6 / RFC6125 / RFC1034
    """
    sans = csr.get_extensions(extension.X509ExtensionSubjectAltName)
    if not sans:
        return

    ext = sans[0]
    for domain in ext.get_dns_ids():
        try:
            util.verify_domain(domain, allow_wildcards=True)
        except ValueError as e:
            raise errors.ValidationError(str(e))
Exemplo n.º 18
0
def server_group(auth_result=None, csr=None, group_prefixes={}, **kwargs):
    """Check Team prefix.

    Make sure that for server names containing a team prefix, the team is
    verified against the groups the user is a member of.
    """

    cn = utils.csr_require_cn(csr)
    parts = cn.split('-')
    if len(parts) == 1 or '.' in parts[0]:
        return  # no prefix

    if parts[0] in group_prefixes:
        if group_prefixes[parts[0]] not in auth_result.groups:
            raise v_errors.ValidationError(
                "Server prefix doesn't match user groups")
Exemplo n.º 19
0
def _valid_domains(csr, label_re="^[a-z](?:[-a-z0-9]*[a-z0-9])?$"):
    """Format of the domin names

    See RFC5280 section 4.2.1.6 / RFC6125 / RFC1034
    """
    sans = csr.get_extensions(extension.X509ExtensionSubjectAltName)
    if not sans:
        return

    label_re_comp = re.compile(label_re, re.IGNORECASE)

    ext = sans[0]
    for domain in ext.get_dns_ids():
        try:
            util.verify_domain(domain, label_re_comp, allow_wildcards=True)
        except ValueError as e:
            raise errors.ValidationError(str(e))