Пример #1
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:
        for domain in config.namespace.domains:
            # This may be redundant, but let's be paranoid
            le_util.enforce_domain_sanity(domain)
Пример #2
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:
        for domain in config.namespace.domains:
            # This may be redundant, but let's be paranoid
            le_util.enforce_domain_sanity(domain)
Пример #3
0
def _reconstitute(config, full_path):
    """Try to instantiate a RenewableCert, updating config with relevant items.

    This is specifically for use in renewal and enforces several checks
    and policies to ensure that we can try to proceed with the renwal
    request. The config argument is modified by including relevant options
    read from the renewal configuration file.

    :param configuration.NamespaceConfig config: configuration for the
        current lineage
    :param str full_path: Absolute path to the configuration file that
        defines this lineage

    :returns: the RenewableCert object or None if a fatal error occurred
    :rtype: `storage.RenewableCert` or NoneType

    """
    try:
        renewal_candidate = storage.RenewableCert(
            full_path, configuration.RenewerConfiguration(config))
    except (errors.CertStorageError, IOError):
        logger.warning("Renewal configuration file %s is broken. Skipping.", full_path)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None
    if "renewalparams" not in renewal_candidate.configuration:
        logger.warning("Renewal configuration file %s lacks "
                       "renewalparams. Skipping.", full_path)
        return None
    renewalparams = renewal_candidate.configuration["renewalparams"]
    if "authenticator" not in renewalparams:
        logger.warning("Renewal configuration file %s does not specify "
                       "an authenticator. Skipping.", full_path)
        return None
    # Now restore specific values along with their data types, if
    # those elements are present.
    try:
        _restore_required_config_elements(config, renewalparams)
        _restore_plugin_configs(config, renewalparams)
    except (ValueError, errors.Error) as error:
        logger.warning(
            "An error occurred while parsing %s. The error was %s. "
            "Skipping the file.", full_path, error.message)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None

    try:
        config.domains = [le_util.enforce_domain_sanity(d)
                          for d in renewal_candidate.names()]
    except errors.ConfigurationError as error:
        logger.warning("Renewal configuration file %s references a cert "
                       "that contains an invalid domain name. The problem "
                       "was: %s. Skipping.", full_path, error)
        return None

    return renewal_candidate
Пример #4
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)))
Пример #5
0
def get_valid_domains(domains):
    """Helper method for choose_names that implements basic checks
     on domain names

    :param list domains: Domain names to validate
    :return: List of valid domains
    :rtype: list
    """
    valid_domains = []
    for domain in domains:
        try:
            valid_domains.append(le_util.enforce_domain_sanity(domain))
        except errors.ConfigurationError:
            continue
    return valid_domains
Пример #6
0
def get_valid_domains(domains):
    """Helper method for choose_names that implements basic checks
     on domain names

    :param list domains: Domain names to validate
    :return: List of valid domains
    :rtype: list
    """
    valid_domains = []
    for domain in domains:
        try:
            valid_domains.append(le_util.enforce_domain_sanity(domain))
        except errors.ConfigurationError:
            continue
    return valid_domains
Пример #7
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)))
Пример #8
0
def _choose_names_manually():
    """Manually input names for those without an installer."""

    code, input_ = z_util(interfaces.IDisplay).input(
        "Please enter in your domain name(s) (comma and/or space separated) ",
        cli_flag="--domains")

    if code == display_util.OK:
        invalid_domains = dict()
        retry_message = ""
        try:
            domain_list = display_util.separate_list_input(input_)
        except UnicodeEncodeError:
            domain_list = []
            retry_message = (
                "Internationalized domain names are not presently "
                "supported.{0}{0}Would you like to re-enter the "
                "names?{0}").format(os.linesep)

        for i, domain in enumerate(domain_list):
            try:
                domain_list[i] = le_util.enforce_domain_sanity(domain)
            except errors.ConfigurationError as e:
                invalid_domains[domain] = e.message

        if len(invalid_domains):
            retry_message = (
                "One or more of the entered domain names was not valid:"
                "{0}{0}").format(os.linesep)
            for domain in invalid_domains:
                retry_message = retry_message + "{1}: {2}{0}".format(
                    os.linesep, domain, invalid_domains[domain])
            retry_message = retry_message + (
                "{0}Would you like to re-enter the names?{0}").format(
                    os.linesep)

        if retry_message:
            # We had error in input
            retry = z_util(interfaces.IDisplay).yesno(retry_message)
            if retry:
                return _choose_names_manually()
        else:
            return domain_list
    return []
Пример #9
0
def _choose_names_manually():
    """Manually input names for those without an installer."""

    code, input_ = z_util(interfaces.IDisplay).input(
        "Please enter in your domain name(s) (comma and/or space separated) ",
        cli_flag="--domains")

    if code == display_util.OK:
        invalid_domains = dict()
        retry_message = ""
        try:
            domain_list = display_util.separate_list_input(input_)
        except UnicodeEncodeError:
            domain_list = []
            retry_message = (
                "Internationalized domain names are not presently "
                "supported.{0}{0}Would you like to re-enter the "
                "names?{0}").format(os.linesep)

        for i, domain in enumerate(domain_list):
            try:
                domain_list[i] = le_util.enforce_domain_sanity(domain)
            except errors.ConfigurationError as e:
                invalid_domains[domain] = e.message

        if len(invalid_domains):
            retry_message = (
                "One or more of the entered domain names was not valid:"
                "{0}{0}").format(os.linesep)
            for domain in invalid_domains:
                retry_message = retry_message + "{1}: {2}{0}".format(
                    os.linesep, domain, invalid_domains[domain])
            retry_message = retry_message + (
                "{0}Would you like to re-enter the names?{0}").format(
                    os.linesep)

        if retry_message:
            # We had error in input
            retry = z_util(interfaces.IDisplay).yesno(retry_message)
            if retry:
                return _choose_names_manually()
        else:
            return domain_list
    return []
Пример #10
0
def process_domain(args_or_config, domain_arg, webroot_path=None):
    """
    Process a new -d flag, helping the webroot plugin construct a map of
    {domain : webrootpath} if -w / --webroot-path is in use

    :param args_or_config: may be an argparse args object, or a NamespaceConfig object
    :param str domain_arg: a string representing 1+ domains, eg: "eg.is, example.com"
    :param str webroot_path: (optional) the webroot_path for these domains

    """
    webroot_path = webroot_path if webroot_path else args_or_config.webroot_path

    for domain in (d.strip() for d in domain_arg.split(",")):
        domain = le_util.enforce_domain_sanity(domain)
        if domain not in args_or_config.domains:
            args_or_config.domains.append(domain)
            # Each domain has a webroot_path of the most recent -w flag
            # unless it was explicitly included in webroot_map
            if webroot_path:
                args_or_config.webroot_map.setdefault(domain, webroot_path[-1])
Пример #11
0
def process_domain(args_or_config, domain_arg, webroot_path=None):
    """
    Process a new -d flag, helping the webroot plugin construct a map of
    {domain : webrootpath} if -w / --webroot-path is in use

    :param args_or_config: may be an argparse args object, or a NamespaceConfig object
    :param str domain_arg: a string representing 1+ domains, eg: "eg.is, example.com"
    :param str webroot_path: (optional) the webroot_path for these domains

    """
    webroot_path = webroot_path if webroot_path else args_or_config.webroot_path

    for domain in (d.strip() for d in domain_arg.split(",")):
        domain = le_util.enforce_domain_sanity(domain)
        if domain not in args_or_config.domains:
            args_or_config.domains.append(domain)
            # Each domain has a webroot_path of the most recent -w flag
            # unless it was explicitly included in webroot_map
            if webroot_path:
                args_or_config.webroot_map.setdefault(domain, webroot_path[-1])
Пример #12
0
def add_domains(args_or_config, domains):
    """Registers new domains to be used during the current client run.

    Domains are not added to the list of requested domains if they have
    already been registered.

    :param args_or_config: parsed command line arguments
    :type args_or_config: argparse.Namespace or
        configuration.NamespaceConfig
    :param str domain: one or more comma separated domains

    :returns: domains after they have been normalized and validated
    :rtype: `list` of `str`

    """
    validated_domains = []
    for domain in domains.split(","):
        domain = le_util.enforce_domain_sanity(domain.strip())
        validated_domains.append(domain)
        if domain not in args_or_config.domains:
            args_or_config.domains.append(domain)

    return validated_domains
Пример #13
0
def add_domains(args_or_config, domains):
    """Registers new domains to be used during the current client run.

    Domains are not added to the list of requested domains if they have
    already been registered.

    :param args_or_config: parsed command line arguments
    :type args_or_config: argparse.Namespace or
        configuration.NamespaceConfig
    :param str domain: one or more comma separated domains

    :returns: domains after they have been normalized and validated
    :rtype: `list` of `str`

    """
    validated_domains = []
    for domain in domains.split(","):
        domain = le_util.enforce_domain_sanity(domain.strip())
        validated_domains.append(domain)
        if domain not in args_or_config.domains:
            args_or_config.domains.append(domain)

    return validated_domains
Пример #14
0
def _reconstitute(config, full_path):
    """Try to instantiate a RenewableCert, updating config with relevant items.

    This is specifically for use in renewal and enforces several checks
    and policies to ensure that we can try to proceed with the renwal
    request. The config argument is modified by including relevant options
    read from the renewal configuration file.

    :param configuration.NamespaceConfig config: configuration for the
        current lineage
    :param str full_path: Absolute path to the configuration file that
        defines this lineage

    :returns: the RenewableCert object or None if a fatal error occurred
    :rtype: `storage.RenewableCert` or NoneType

    """
    try:
        renewal_candidate = storage.RenewableCert(
            full_path, configuration.RenewerConfiguration(config))
    except (errors.CertStorageError, IOError):
        logger.warning("Renewal configuration file %s is broken. Skipping.",
                       full_path)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None
    if "renewalparams" not in renewal_candidate.configuration:
        logger.warning(
            "Renewal configuration file %s lacks "
            "renewalparams. Skipping.", full_path)
        return None
    renewalparams = renewal_candidate.configuration["renewalparams"]
    if "authenticator" not in renewalparams:
        logger.warning(
            "Renewal configuration file %s does not specify "
            "an authenticator. Skipping.", full_path)
        return None
    # Now restore specific values along with their data types, if
    # those elements are present.
    try:
        _restore_required_config_elements(config, renewalparams)
        _restore_plugin_configs(config, renewalparams)
    except (ValueError, errors.Error) as error:
        logger.warning(
            "An error occurred while parsing %s. The error was %s. "
            "Skipping the file.", full_path, error.message)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None

    try:
        config.domains = [
            le_util.enforce_domain_sanity(d)
            for d in renewal_candidate.names()
        ]
    except errors.ConfigurationError as error:
        logger.warning(
            "Renewal configuration file %s references a cert "
            "that contains an invalid domain name. The problem "
            "was: %s. Skipping.", full_path, error)
        return None

    return renewal_candidate
Пример #15
0
 def _call(self, domain):
     from letsencrypt.le_util import enforce_domain_sanity
     return enforce_domain_sanity(domain)