Esempio n. 1
0
def _check_config_domain_sanity(domains):
    """Helper method for check_config_sanity which validates
    domain flag values and errors out if the requirements are not met.

    :param domains: List of domains
    :type domains: `list` of `string`
    :raises ConfigurationError: for invalid domains and cases where Let's
                                Encrypt currently will not issue certificates

    """
    # Check if there's a wildcard domain
    if any(d.startswith("*.") for d in domains):
        raise errors.ConfigurationError(
            "Wildcard domains are not supported")
    # Punycode
    if any("xn--" in d for d in domains):
        raise errors.ConfigurationError(
            "Punycode domains are not supported")

    # Unicode
    try:
        for domain in domains:
            domain.encode('ascii')
    except UnicodeDecodeError:
        raise errors.ConfigurationError(
            "Internationalized domain names are not supported")

    # FQDN checks from
    # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
    #  Characters used, domain parts < 63 chars, tld > 1 < 64 chars
    #  first and last char is not "-"
    fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,63}$")
    if any(True for d in domains if not fqdn.match(d)):
        raise errors.ConfigurationError("Requested domain is not a FQDN")
Esempio n. 2
0
    def handle_csr(self, parsed_args):
        """
        Process a --csr flag. This needs to happen early enough that the
        webroot plugin can know about the calls to process_domain
        """
        if parsed_args.verb != "certonly":
            raise errors.Error("Currently, a CSR file may only be specified "
                               "when obtaining a new or replacement "
                               "via the certonly command. Please try the "
                               "certonly command instead.")

        try:
            csr = le_util.CSR(file=parsed_args.csr[0],
                              data=parsed_args.csr[1],
                              form="der")
            typ = OpenSSL.crypto.FILETYPE_ASN1
            domains = crypto_util.get_sans_from_csr(
                csr.data, OpenSSL.crypto.FILETYPE_ASN1)
        except OpenSSL.crypto.Error:
            try:
                e1 = traceback.format_exc()
                typ = OpenSSL.crypto.FILETYPE_PEM
                csr = le_util.CSR(file=parsed_args.csr[0],
                                  data=parsed_args.csr[1],
                                  form="pem")
                domains = crypto_util.get_sans_from_csr(csr.data, typ)
            except OpenSSL.crypto.Error:
                logger.debug("DER CSR parse error %s", e1)
                logger.debug("PEM CSR parse error %s", traceback.format_exc())
                raise errors.Error("Failed to parse CSR file: {0}".format(
                    parsed_args.csr[0]))
        for d in domains:
            process_domain(parsed_args, d)

        for d in domains:
            sanitised = le_util.enforce_domain_sanity(d)
            if d.lower() != sanitised:
                raise errors.ConfigurationError(
                    "CSR domain {0} needs to be sanitised to {1}.".format(
                        d, sanitised))

        if not domains:
            # TODO: add CN to domains instead:
            raise errors.Error(
                "Unfortunately, your CSR %s needs to have a SubjectAltName for every domain"
                % parsed_args.csr[0])

        parsed_args.actual_csr = (csr, typ)
        csr_domains, config_domains = set(domains), set(parsed_args.domains)
        if csr_domains != config_domains:
            raise errors.ConfigurationError(
                "Inconsistent domain requests:\nFrom the CSR: {0}\nFrom command line/config: {1}"
                .format(", ".join(csr_domains), ", ".join(config_domains)))
Esempio n. 3
0
def enforce_domain_sanity(domain):
    """Method which validates domain value and errors out if
    the requirements are not met.

    :param domain: Domain to check
    :type domains: `str` or `unicode`
    :raises ConfigurationError: for invalid domains and cases where Let's
                                Encrypt currently will not issue certificates

    :returns: The domain cast to `str`, with ASCII-only contents
    :rtype: str
    """
    # Check if there's a wildcard domain
    if domain.startswith("*."):
        raise errors.ConfigurationError(
            "Wildcard domains are not supported: {0}".format(domain))
    # Punycode
    if "xn--" in domain:
        raise errors.ConfigurationError(
            "Punycode domains are not presently supported: {0}".format(domain))

    # Unicode
    try:
        domain = domain.encode('ascii').lower()
    except UnicodeDecodeError:
        raise errors.ConfigurationError(
            "Internationalized domain names are not presently supported: {0}"
            .format(domain))

    # Remove trailing dot
    domain = domain[:-1] if domain.endswith('.') else domain

    # Explain separately that IP addresses aren't allowed (apart from not
    # being FQDNs) because hope springs eternal concerning this point
    try:
        socket.inet_aton(domain)
        raise errors.ConfigurationError(
            "Requested name {0} is an IP address. The Let's Encrypt "
            "certificate authority will not issue certificates for a "
            "bare IP address.".format(domain))
    except socket.error:
        # It wasn't an IP address, so that's good
        pass

    # FQDN checks from
    # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
    #  Characters used, domain parts < 63 chars, tld > 1 < 64 chars
    #  first and last char is not "-"
    fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,63}$")
    if not fqdn.match(domain):
        raise errors.ConfigurationError("Requested domain {0} is not a FQDN".format(domain))
    return domain
Esempio n. 4
0
def enforce_domain_sanity(domain):
    """Method which validates domain value and errors out if
    the requirements are not met.

    :param domain: Domain to check
    :type domains: `str` or `unicode`
    :raises ConfigurationError: for invalid domains and cases where Let's
                                Encrypt currently will not issue certificates

    :returns: The domain cast to `str`, with ASCII-only contents
    :rtype: str
    """
    # Check if there's a wildcard domain
    if domain.startswith("*."):
        raise errors.ConfigurationError(
            "Wildcard domains are not supported: {0}".format(domain))
    # Punycode
    if "xn--" in domain:
        raise errors.ConfigurationError(
            "Punycode domains are not presently supported: {0}".format(domain))

    # Unicode
    try:
        domain = domain.encode('ascii')
    except UnicodeDecodeError:
        raise errors.ConfigurationError(
            "Internationalized domain names are not presently supported: {0}".
            format(domain))

    # Remove trailing dot
    domain = domain[:-1] if domain.endswith('.') else domain

    # FQDN checks from
    # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/
    #  Characters used, domain parts < 63 chars, tld > 1 < 64 chars
    #  first and last char is not "-"
    fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,63}$")
    if not fqdn.match(domain):
        raise errors.ConfigurationError(
            "Requested domain {0} is not a FQDN".format(domain))
    return domain
Esempio n. 5
0
def check_config_sanity(config):
    """Validate command line options and display error message if
    requirements are not met.

    :param config: IConfig instance holding user configuration
    :type args: :class:`letsencrypt.interfaces.IConfig`

    """
    # Port check
    if config.http01_port == config.tls_sni_01_port:
        raise errors.ConfigurationError(
            "Trying to run http-01 and tls-sni-01 "
            "on the same port ({0})".format(config.tls_sni_01_port))

    # Domain checks
    if config.namespace.domains is not None:
        _check_config_domain_sanity(config.namespace.domains)
Esempio n. 6
0
    def handle_csr(self, parsed_args):
        """Process a --csr flag."""
        if parsed_args.verb != "certonly":
            raise errors.Error("Currently, a CSR file may only be specified "
                               "when obtaining a new or replacement "
                               "via the certonly command. Please try the "
                               "certonly command instead.")

        try:
            csr = le_util.CSR(file=parsed_args.csr[0],
                              data=parsed_args.csr[1],
                              form="der")
            typ = OpenSSL.crypto.FILETYPE_ASN1
            domains = crypto_util.get_sans_from_csr(
                csr.data, OpenSSL.crypto.FILETYPE_ASN1)
        except OpenSSL.crypto.Error:
            try:
                e1 = traceback.format_exc()
                typ = OpenSSL.crypto.FILETYPE_PEM
                csr = le_util.CSR(file=parsed_args.csr[0],
                                  data=parsed_args.csr[1],
                                  form="pem")
                domains = crypto_util.get_sans_from_csr(csr.data, typ)
            except OpenSSL.crypto.Error:
                logger.debug("DER CSR parse error %s", e1)
                logger.debug("PEM CSR parse error %s", traceback.format_exc())
                raise errors.Error("Failed to parse CSR file: {0}".format(
                    parsed_args.csr[0]))

        # This is not necessary for webroot to work, however,
        # obtain_certificate_from_csr requires parsed_args.domains to be set
        for domain in domains:
            add_domains(parsed_args, domain)

        if not domains:
            # TODO: add CN to domains instead:
            raise errors.Error(
                "Unfortunately, your CSR %s needs to have a SubjectAltName for every domain"
                % parsed_args.csr[0])

        parsed_args.actual_csr = (csr, typ)
        csr_domains, config_domains = set(domains), set(parsed_args.domains)
        if csr_domains != config_domains:
            raise errors.ConfigurationError(
                "Inconsistent domain requests:\nFrom the CSR: {0}\nFrom command line/config: {1}"
                .format(", ".join(csr_domains), ", ".join(config_domains)))