Exemple #1
0
def _report_new_cert(config, cert_path, fullchain_path):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain

    """
    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    if fullchain_path:
        # Print the path to fullchain.pem because that's what modern webservers
        # (Nginx and Apache2.4) will want.
        and_chain = "and chain have"
        path = fullchain_path
    else:
        # Unless we're in .csr mode and there really isn't one
        and_chain = "has "
        path = cert_path

    verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = ('Congratulations! Your certificate {0} been saved at {1}.'
           ' Your cert will expire on {2}. To obtain a new or tweaked version of this '
           'certificate in the future, simply run {3} again{4}. '
           'To non-interactively renew *all* of your ceriticates, run "{3} renew"'
           .format(and_chain, path, expiry, cli.cli_command, verbswitch))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #2
0
def _report_new_cert(cert_path, fullchain_path):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain

    """
    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    if fullchain_path:
        # Print the path to fullchain.pem because that's what modern webservers
        # (Nginx and Apache2.4) will want.
        and_chain = "and chain have"
        path = fullchain_path
    else:
        # Unless we're in .csr mode and there really isn't one
        and_chain = "has "
        path = cert_path
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = ("Congratulations! Your certificate {0} been saved at {1}."
           " Your cert will expire on {2}. To obtain a new version of the "
           "certificate in the future, simply run Certbot again."
           .format(and_chain, path, expiry))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #3
0
    def target_expiry(self):
        """The current target certificate's expiration datetime

        :returns: Expiration datetime of the current target certificate
        :rtype: :class:`datetime.datetime`
        """
        return crypto_util.notAfter(self.current_target("cert"))
Exemple #4
0
    def ocsp_revoked_by_paths(self,
                              cert_path: str,
                              chain_path: str,
                              timeout: int = 10) -> bool:
        """Performs the OCSP revocation check

        :param str cert_path: Certificate filepath
        :param str chain_path: Certificate chain
        :param int timeout: Timeout (in seconds) for the OCSP query

        :returns: True if revoked; False if valid or the check failed or cert is expired.
        :rtype: bool

        """
        if self.broken:
            return False

        # Let's Encrypt doesn't update OCSP for expired certificates,
        # so don't check OCSP if the cert is expired.
        # https://github.com/certbot/certbot/issues/7152
        now = pytz.UTC.fromutc(datetime.utcnow())
        if crypto_util.notAfter(cert_path) <= now:
            return False

        url, host = _determine_ocsp_server(cert_path)
        if not host or not url:
            return False

        if self.use_openssl_binary:
            return self._check_ocsp_openssl_bin(cert_path, chain_path, host,
                                                url, timeout)
        return _check_ocsp_cryptography(cert_path, chain_path, url, timeout)
Exemple #5
0
def _report_new_cert(config, cert_path, fullchain_path):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain

    """
    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    if fullchain_path:
        # Print the path to fullchain.pem because that's what modern webservers
        # (Nginx and Apache2.4) will want.
        and_chain = "and chain have"
        path = fullchain_path
    else:
        # Unless we're in .csr mode and there really isn't one
        and_chain = "has "
        path = cert_path

    verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = ('Congratulations! Your certificate {0} been saved at {1}.'
           ' Your cert will expire on {2}. To obtain a new or tweaked version of this '
           'certificate in the future, simply run {3} again{4}. '
           'To non-interactively renew *all* of your certificates, run "{3} renew"'
           .format(and_chain, path, expiry, cli.cli_command, verbswitch))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #6
0
def _report_new_cert(cert_path, fullchain_path):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain

    """
    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    if fullchain_path:
        # Print the path to fullchain.pem because that's what modern webservers
        # (Nginx and Apache2.4) will want.
        and_chain = "and chain have"
        path = fullchain_path
    else:
        # Unless we're in .csr mode and there really isn't one
        and_chain = "has "
        path = cert_path
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = (
        "Congratulations! Your certificate {0} been saved at {1}."
        " Your cert will expire on {2}. To obtain a new version of the "
        "certificate in the future, simply run Certbot again.".format(and_chain, path, expiry)
    )
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #7
0
def _report_new_cert(config, cert_path, fullchain_path):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain

    """
    if config.dry_run:
        _report_successful_dry_run(config)
        return

    assert cert_path and fullchain_path, "No certificates saved to report."

    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    # Print the path to fullchain.pem because that's what modern webservers
    # (Nginx and Apache2.4) will want.

    verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = (
        'Congratulations! Your certificate and chain have been saved at {0}.'
        ' Your cert will expire on {1}. To obtain a new or tweaked version of this '
        'certificate in the future, simply run {2} again{3}. '
        'To non-interactively renew *all* of your certificates, run "{2} renew"'
        .format(fullchain_path, expiry, cli.cli_command, verbswitch))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
    print("Voy a copiar")
    copyfile(fullchain_path, "../../ObtainedCERT.pem")
Exemple #8
0
    def ocsp_revoked(self, cert):
        # type: (RenewableCert) -> bool
        """Get revoked status for a particular cert version.

        .. todo:: Make this a non-blocking call

        :param `.interfaces.RenewableCert` cert: Certificate object
        :returns: True if revoked; False if valid or the check failed or cert is expired.
        :rtype: bool

        """
        cert_path, chain_path = cert.cert_path, cert.chain_path

        if self.broken:
            return False

        # Let's Encrypt doesn't update OCSP for expired certificates,
        # so don't check OCSP if the cert is expired.
        # https://github.com/certbot/certbot/issues/7152
        now = pytz.UTC.fromutc(datetime.utcnow())
        if crypto_util.notAfter(cert_path) <= now:
            return False

        url, host = _determine_ocsp_server(cert_path)
        if not host or not url:
            return False

        if self.use_openssl_binary:
            return self._check_ocsp_openssl_bin(cert_path, chain_path, host,
                                                url)
        return _check_ocsp_cryptography(cert_path, chain_path, url)
Exemple #9
0
    def should_autodeploy(self, interactive=False):
        """Should this lineage now automatically deploy a newer version?

        This is a policy question and does not only depend on whether
        there is a newer version of the cert. (This considers whether
        autodeployment is enabled, whether a relevant newer version
        exists, and whether the time interval for autodeployment has
        been reached.)

        :param bool interactive: set to True to examine the question
            regardless of whether the renewal configuration allows
            automated deployment (for interactive use). Default False.

        :returns: whether the lineage now ought to autodeploy an
            existing newer cert version
        :rtype: bool

        """
        if interactive or self.autodeployment_is_enabled():
            if self.has_pending_deployment():
                interval = self.configuration.get("deploy_before_expiry",
                                                  "5 days")
                expiry = crypto_util.notAfter(self.current_target("cert"))
                now = pytz.UTC.fromutc(datetime.datetime.utcnow())
                if expiry < add_time_interval(now, interval):
                    return True
        return False
Exemple #10
0
    def target_expiry(self):
        """The current target certificate's expiration datetime

        :returns: Expiration datetime of the current target certificate
        :rtype: :class:`datetime.datetime`
        """
        return crypto_util.notAfter(self.current_target("cert"))
Exemple #11
0
def _report_new_cert(config, cert_path, fullchain_path, key_path=None):
    """Reports the creation of a new certificate to the user.

    :param str cert_path: path to cert
    :param str fullchain_path: path to full chain
    :param str key_path: path to private key, if available

    """
    if config.dry_run:
        _report_successful_dry_run(config)
        return

    assert cert_path and fullchain_path, "No certificates saved to report."

    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    # Print the path to fullchain.pem because that's what modern webservers
    # (Nginx and Apache2.4) will want.

    verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
    privkey_statement = 'Your key file has been saved at:{br}{0}{br}'.format(
            key_path, br=os.linesep) if key_path else ""
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = ('Congratulations! Your certificate and chain have been saved at:{br}'
           '{0}{br}{1}'
           'Your cert will expire on {2}. To obtain a new or tweaked version of this '
           'certificate in the future, simply run {3} again{4}. '
           'To non-interactively renew *all* of your certificates, run "{3} renew"'
           .format(fullchain_path, privkey_statement, expiry, cli.cli_command, verbswitch,
               br=os.linesep))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #12
0
    def should_autodeploy(self, interactive=False):
        """Should this lineage now automatically deploy a newer version?

        This is a policy question and does not only depend on whether
        there is a newer version of the cert. (This considers whether
        autodeployment is enabled, whether a relevant newer version
        exists, and whether the time interval for autodeployment has
        been reached.)

        :param bool interactive: set to True to examine the question
            regardless of whether the renewal configuration allows
            automated deployment (for interactive use). Default False.

        :returns: whether the lineage now ought to autodeploy an
            existing newer cert version
        :rtype: bool

        """
        if interactive or self.autodeployment_is_enabled():
            if self.has_pending_deployment():
                interval = self.configuration.get("deploy_before_expiry",
                                                  "5 days")
                expiry = crypto_util.notAfter(self.current_target("cert"))
                now = pytz.UTC.fromutc(datetime.datetime.utcnow())
                if expiry < add_time_interval(now, interval):
                    return True
        return False
Exemple #13
0
def _report_new_cert(config, cert_path, fullchain_path, key_path=None):
    """Reports the creation of a new certificate to the user.

    :param cert_path: path to certificate
    :type cert_path: str

    :param fullchain_path: path to full chain
    :type fullchain_path: str

    :param key_path: path to private key, if available
    :type key_path: str

    :returns: `None`
    :rtype: None

    """
    if config.dry_run:
        _report_successful_dry_run(config)
        return

    assert cert_path and fullchain_path, "No certificates saved to report."

    expiry = crypto_util.notAfter(cert_path).date()
    reporter_util = zope.component.getUtility(interfaces.IReporter)
    # Print the path to fullchain.pem because that's what modern webservers
    # (Nginx and Apache2.4) will want.

    verbswitch = ' with the "certonly" option' if config.verb == "run" else ""
    privkey_statement = 'Your key file has been saved at:{br}{0}{br}'.format(
        key_path, br=os.linesep) if key_path else ""
    # XXX Perhaps one day we could detect the presence of known old webservers
    # and say something more informative here.
    msg = (
        'Congratulations! Your certificate and chain have been saved at:{br}'
        '{0}{br}{1}'
        'Your cert will expire on {2}. To obtain a new or tweaked version of this '
        'certificate in the future, simply run {3} again{4}. '
        'To non-interactively renew *all* of your certificates, run "{3} renew"'
        .format(fullchain_path,
                privkey_statement,
                expiry,
                cli.cli_command,
                verbswitch,
                br=os.linesep))
    reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY)
Exemple #14
0
    def should_autorenew(self, interactive=False):
        """Should we now try to autorenew the most recent cert version?

        This is a policy question and does not only depend on whether
        the cert is expired. (This considers whether autorenewal is
        enabled, whether the cert is revoked, and whether the time
        interval for autorenewal has been reached.)

        Note that this examines the numerically most recent cert version,
        not the currently deployed version.

        :param bool interactive: set to True to examine the question
            regardless of whether the renewal configuration allows
            automated renewal (for interactive use). Default False.

        :returns: whether an attempt should now be made to autorenew the
            most current cert version in this lineage
        :rtype: bool

        """
        if interactive or self.autorenewal_is_enabled():
            # Consider whether to attempt to autorenew this cert now

            # Renewals on the basis of revocation
            if self.ocsp_revoked(self.latest_common_version()):
                logger.debug("Should renew, certificate is revoked.")
                return True

            # Renews some period before expiry time
            default_interval = constants.RENEWER_DEFAULTS[
                "renew_before_expiry"]
            interval = self.configuration.get("renew_before_expiry",
                                              default_interval)
            expiry = crypto_util.notAfter(
                self.version("cert", self.latest_common_version()))
            now = pytz.UTC.fromutc(datetime.datetime.utcnow())
            if expiry < add_time_interval(now, interval):
                logger.debug(
                    "Should renew, less than %s before certificate "
                    "expiry %s.", interval,
                    expiry.strftime("%Y-%m-%d %H:%M:%S %Z"))
                return True
        return False
Exemple #15
0
    def should_autorenew(self, interactive=False):
        """Should we now try to autorenew the most recent cert version?

        This is a policy question and does not only depend on whether
        the cert is expired. (This considers whether autorenewal is
        enabled, whether the cert is revoked, and whether the time
        interval for autorenewal has been reached.)

        Note that this examines the numerically most recent cert version,
        not the currently deployed version.

        :param bool interactive: set to True to examine the question
            regardless of whether the renewal configuration allows
            automated renewal (for interactive use). Default False.

        :returns: whether an attempt should now be made to autorenew the
            most current cert version in this lineage
        :rtype: bool

        """
        if interactive or self.autorenewal_is_enabled():
            # Consider whether to attempt to autorenew this cert now

            # Renewals on the basis of revocation
            if self.ocsp_revoked(self.latest_common_version()):
                logger.debug("Should renew, certificate is revoked.")
                return True

            # Renews some period before expiry time
            default_interval = constants.RENEWER_DEFAULTS["renew_before_expiry"]
            interval = self.configuration.get("renew_before_expiry", default_interval)
            expiry = crypto_util.notAfter(self.version(
                "cert", self.latest_common_version()))
            now = pytz.UTC.fromutc(datetime.datetime.utcnow())
            if expiry < add_time_interval(now, interval):
                logger.debug("Should renew, less than %s before certificate "
                             "expiry %s.", interval,
                             expiry.strftime("%Y-%m-%d %H:%M:%S %Z"))
                return True
        return False
Exemple #16
0
 def test_notAfter(self):
     from certbot.crypto_util import notAfter
     self.assertEqual(
         notAfter(CERT_PATH).isoformat(), '2014-12-18T22:34:45+00:00')
 def test_notAfter(self):
     from certbot.crypto_util import notAfter
     self.assertEqual(notAfter(CERT_PATH).isoformat(),
                      '2014-12-18T22:34:45+00:00')
Exemple #18
0
def handle_renewal_request(config):
    """Examine each lineage; renew if due and report results"""

    # This is trivially False if config.domains is empty
    if any(domain not in config.webroot_map for domain in config.domains):
        # If more plugins start using cli.add_domains,
        # we may want to only log a warning here
        raise errors.Error(
            "Currently, the renew verb is capable of either "
            "renewing all installed certificates that are due "
            "to be renewed or renewing a single certificate specified "
            "by its name. If you would like to renew specific "
            "certificates by their domains, use the certonly command "
            "instead. The renew verb may provide other options "
            "for selecting certificates to renew in the future.")

    if config.certname:
        conf_files = [
            storage.renewal_file_for_certname(config, config.certname)
        ]
    else:
        conf_files = storage.renewal_conf_files(config)

    renew_successes = []
    renew_failures = []
    renew_skipped = []
    parse_failures = []

    # Noninteractive renewals include a random delay in order to spread
    # out the load on the certificate authority servers, even if many
    # users all pick the same time for renewals.  This delay precedes
    # running any hooks, so that side effects of the hooks (such as
    # shutting down a web service) aren't prolonged unnecessarily.
    apply_random_sleep = not sys.stdin.isatty(
    ) and config.random_sleep_on_renew

    for renewal_file in conf_files:
        display_util.notification("Processing " + renewal_file, pause=False)
        lineage_config = copy.deepcopy(config)
        lineagename = storage.lineagename_for_filename(renewal_file)

        # Note that this modifies config (to add back the configuration
        # elements from within the renewal configuration file).
        try:
            renewal_candidate = _reconstitute(lineage_config, renewal_file)
        except Exception as e:  # pylint: disable=broad-except
            logger.error(
                "Renewal configuration file %s (cert: %s) "
                "produced an unexpected error: %s. Skipping.", renewal_file,
                lineagename, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            parse_failures.append(renewal_file)
            continue

        try:
            if renewal_candidate is None:
                parse_failures.append(renewal_file)
            else:
                # This call is done only for retro-compatibility purposes.
                # TODO: Remove this call once zope dependencies are removed from Certbot.
                zope.component.provideUtility(lineage_config,
                                              interfaces.IConfig)
                renewal_candidate.ensure_deployed()
                from certbot._internal import main
                plugins = plugins_disco.PluginsRegistry.find_all()
                if should_renew(lineage_config, renewal_candidate):
                    # Apply random sleep upon first renewal if needed
                    if apply_random_sleep:
                        sleep_time = random.uniform(1, 60 * 8)
                        logger.info(
                            "Non-interactive renewal: random delay of %s seconds",
                            sleep_time)
                        time.sleep(sleep_time)
                        # We will sleep only once this day, folks.
                        apply_random_sleep = False

                    # domains have been restored into lineage_config by reconstitute
                    # but they're unnecessary anyway because renew_cert here
                    # will just grab them from the certificate
                    # we already know it's time to renew based on should_renew
                    # and we have a lineage in renewal_candidate
                    main.renew_cert(lineage_config, plugins, renewal_candidate)
                    renew_successes.append(renewal_candidate.fullchain)
                else:
                    expiry = crypto_util.notAfter(
                        renewal_candidate.version(
                            "cert", renewal_candidate.latest_common_version()))
                    renew_skipped.append("%s expires on %s" %
                                         (renewal_candidate.fullchain,
                                          expiry.strftime("%Y-%m-%d")))
                # Run updater interface methods
                updater.run_generic_updaters(lineage_config, renewal_candidate,
                                             plugins)

        except Exception as e:  # pylint: disable=broad-except
            # obtain_cert (presumably) encountered an unanticipated problem.
            logger.error("Failed to renew certificate %s with error: %s",
                         lineagename, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            renew_failures.append(renewal_candidate.fullchain)

    # Describe all the results
    _renew_describe_results(config, renew_successes, renew_failures,
                            renew_skipped, parse_failures)

    if renew_failures or parse_failures:
        raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
            len(renew_failures), len(parse_failures)))

    # Windows installer integration tests rely on handle_renewal_request behavior here.
    # If the text below changes, these tests will need to be updated accordingly.
    logger.debug("no renewal failures")
Exemple #19
0
def handle_renewal_request(config):
    """Examine each lineage; renew if due and report results"""

    # This is trivially False if config.domains is empty
    if any(domain not in config.webroot_map for domain in config.domains):
        # If more plugins start using cli.add_domains,
        # we may want to only log a warning here
        raise errors.Error(
            "Currently, the renew verb is capable of either "
            "renewing all installed certificates that are due "
            "to be renewed or renewing a single certificate specified "
            "by its name. If you would like to renew specific "
            "certificates by their domains, use the certonly command "
            "instead. The renew verb may provide other options "
            "for selecting certificates to renew in the future.")

    if config.certname:
        conf_files = [
            storage.renewal_file_for_certname(config, config.certname)
        ]
    else:
        conf_files = storage.renewal_conf_files(config)

    renew_successes = []
    renew_failures = []
    renew_skipped = []
    parse_failures = []
    for renewal_file in conf_files:
        disp = zope.component.getUtility(interfaces.IDisplay)
        disp.notification("Processing " + renewal_file, pause=False)
        lineage_config = copy.deepcopy(config)
        lineagename = storage.lineagename_for_filename(renewal_file)

        # Note that this modifies config (to add back the configuration
        # elements from within the renewal configuration file).
        try:
            renewal_candidate = _reconstitute(lineage_config, renewal_file)
        except Exception as e:  # pylint: disable=broad-except
            logger.warning(
                "Renewal configuration file %s (cert: %s) "
                "produced an unexpected error: %s. Skipping.", renewal_file,
                lineagename, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            parse_failures.append(renewal_file)
            continue

        try:
            if renewal_candidate is None:
                parse_failures.append(renewal_file)
            else:
                # XXX: ensure that each call here replaces the previous one
                zope.component.provideUtility(lineage_config)
                renewal_candidate.ensure_deployed()
                from certbot import main
                plugins = plugins_disco.PluginsRegistry.find_all()
                if should_renew(lineage_config, renewal_candidate):
                    # domains have been restored into lineage_config by reconstitute
                    # but they're unnecessary anyway because renew_cert here
                    # will just grab them from the certificate
                    # we already know it's time to renew based on should_renew
                    # and we have a lineage in renewal_candidate
                    main.renew_cert(lineage_config, plugins, renewal_candidate)
                    renew_successes.append(renewal_candidate.fullchain)
                else:
                    expiry = crypto_util.notAfter(
                        renewal_candidate.version(
                            "cert", renewal_candidate.latest_common_version()))
                    renew_skipped.append("%s expires on %s" %
                                         (renewal_candidate.fullchain,
                                          expiry.strftime("%Y-%m-%d")))
                # Run updater interface methods
                updater.run_generic_updaters(lineage_config, renewal_candidate,
                                             plugins)

        except Exception as e:  # pylint: disable=broad-except
            # obtain_cert (presumably) encountered an unanticipated problem.
            logger.warning(
                "Attempting to renew cert (%s) from %s produced an "
                "unexpected error: %s. Skipping.", lineagename, renewal_file,
                e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            renew_failures.append(renewal_candidate.fullchain)

    # Describe all the results
    _renew_describe_results(config, renew_successes, renew_failures,
                            renew_skipped, parse_failures)

    if renew_failures or parse_failures:
        raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
            len(renew_failures), len(parse_failures)))
    else:
        logger.debug("no renewal failures")
Exemple #20
0
def handle_renewal_request(config):
    """Examine each lineage; renew if due and report results"""

    # This is trivially False if config.domains is empty
    if any(domain not in config.webroot_map for domain in config.domains):
        # If more plugins start using cli.add_domains,
        # we may want to only log a warning here
        raise errors.Error("Currently, the renew verb is capable of either "
                           "renewing all installed certificates that are due "
                           "to be renewed or renewing a single certificate specified "
                           "by its name. If you would like to renew specific "
                           "certificates by their domains, use the certonly command "
                           "instead. The renew verb may provide other options "
                           "for selecting certificates to renew in the future.")

    if config.certname:
        conf_files = [storage.renewal_file_for_certname(config, config.certname)]
    else:
        conf_files = storage.renewal_conf_files(config)

    renew_successes = []
    renew_failures = []
    renew_skipped = []
    parse_failures = []
    for renewal_file in conf_files:
        disp = zope.component.getUtility(interfaces.IDisplay)
        disp.notification("Processing " + renewal_file, pause=False)
        lineage_config = copy.deepcopy(config)
        lineagename = storage.lineagename_for_filename(renewal_file)

        # Note that this modifies config (to add back the configuration
        # elements from within the renewal configuration file).
        try:
            renewal_candidate = _reconstitute(lineage_config, renewal_file)
        except Exception as e:  # pylint: disable=broad-except
            logger.warning("Renewal configuration file %s (cert: %s) "
                           "produced an unexpected error: %s. Skipping.",
                           renewal_file, lineagename, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            parse_failures.append(renewal_file)
            continue

        try:
            if renewal_candidate is None:
                parse_failures.append(renewal_file)
            else:
                # XXX: ensure that each call here replaces the previous one
                zope.component.provideUtility(lineage_config)
                renewal_candidate.ensure_deployed()
                from certbot import main
                plugins = plugins_disco.PluginsRegistry.find_all()
                if should_renew(lineage_config, renewal_candidate):
                    # domains have been restored into lineage_config by reconstitute
                    # but they're unnecessary anyway because renew_cert here
                    # will just grab them from the certificate
                    # we already know it's time to renew based on should_renew
                    # and we have a lineage in renewal_candidate
                    main.renew_cert(lineage_config, plugins, renewal_candidate)
                    renew_successes.append(renewal_candidate.fullchain)
                else:
                    expiry = crypto_util.notAfter(renewal_candidate.version(
                        "cert", renewal_candidate.latest_common_version()))
                    renew_skipped.append("%s expires on %s" % (renewal_candidate.fullchain,
                                         expiry.strftime("%Y-%m-%d")))
                # Run updater interface methods
                updater.run_generic_updaters(lineage_config, renewal_candidate,
                                             plugins)

        except Exception as e:  # pylint: disable=broad-except
            # obtain_cert (presumably) encountered an unanticipated problem.
            logger.warning("Attempting to renew cert (%s) from %s produced an "
                           "unexpected error: %s. Skipping.", lineagename,
                               renewal_file, e)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            renew_failures.append(renewal_candidate.fullchain)

    # Describe all the results
    _renew_describe_results(config, renew_successes, renew_failures,
                            renew_skipped, parse_failures)

    if renew_failures or parse_failures:
        raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
            len(renew_failures), len(parse_failures)))
    else:
        logger.debug("no renewal failures")