Beispiel #1
0
def init_save_csr(privkey, names, path):
    """Initialize a CSR with the given private key.

    :param privkey: Key to include in the CSR
    :type privkey: :class:`certbot.util.Key`

    :param set names: `str` names to include in the CSR

    :param str path: Certificate save directory.

    :returns: CSR
    :rtype: :class:`certbot.util.CSR`

    """
    config = zope.component.getUtility(interfaces.IConfig)

    csr_pem = acme_crypto_util.make_csr(
        privkey.pem, names, must_staple=config.must_staple)

    # Save CSR
    util.make_or_verify_dir(path, 0o755, os.geteuid(),
                               config.strict_permissions)
    csr_f, csr_filename = util.unique_file(
        os.path.join(path, "csr-certbot.pem"), 0o644, "wb")
    with csr_f:
        csr_f.write(csr_pem)
    logger.debug("Creating CSR: %s", csr_filename)

    return util.CSR(csr_filename, csr_pem, "pem")
Beispiel #2
0
def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
    """Initializes and saves a privkey.

    Inits key and saves it in PEM format on the filesystem.

    .. note:: keyname is the attempted filename, it may be different if a file
        already exists at the path.

    :param int key_size: RSA key size in bits
    :param str key_dir: Key save directory.
    :param str keyname: Filename of key

    :returns: Key
    :rtype: :class:`certbot.util.Key`

    :raises ValueError: If unable to generate the key given key_size.

    """
    try:
        key_pem = make_key(key_size)
    except ValueError as err:
        logger.exception(err)
        raise err

    config = zope.component.getUtility(interfaces.IConfig)
    # Save file
    util.make_or_verify_dir(key_dir, 0o700, os.geteuid(),
                            config.strict_permissions)
    key_f, key_path = util.unique_file(
        os.path.join(key_dir, keyname), 0o600, "wb")
    with key_f:
        key_f.write(key_pem)
    logger.debug("Generating key (%d bits): %s", key_size, key_path)

    return util.Key(key_path, key_pem)
Beispiel #3
0
 def _save(self, account, acme, regr_only):
     account_dir_path = self._account_dir_path(account.id)
     util.make_or_verify_dir(account_dir_path, 0o700, misc.os_geteuid(),
                             self.config.strict_permissions)
     try:
         with open(self._regr_path(account_dir_path), "w") as regr_file:
             regr = account.regr
             # If we have a value for new-authz, save it for forwards
             # compatibility with older versions of Certbot. If we don't
             # have a value for new-authz, this is an ACMEv2 directory where
             # an older version of Certbot won't work anyway.
             if hasattr(acme.directory, "new-authz"):
                 regr = RegistrationResourceWithNewAuthzrURI(
                     new_authzr_uri=acme.directory.new_authz,
                     body={},
                     uri=regr.uri)
             else:
                 regr = messages.RegistrationResource(
                     body={},
                     uri=regr.uri)
             regr_file.write(regr.json_dumps())
         if not regr_only:
             with util.safe_open(self._key_path(account_dir_path),
                                 "w", chmod=0o400) as key_file:
                 key_file.write(account.key.json_dumps())
             with open(self._metadata_path(
                     account_dir_path), "w") as metadata_file:
                 metadata_file.write(account.meta.json_dumps())
     except IOError as error:
         raise errors.AccountStorageError(error)
Beispiel #4
0
def _find_duplicative_certs(config, domains):
    """Find existing certs that duplicate the request."""

    identical_names_cert, subset_names_cert = None, None

    cli_config = configuration.RenewerConfiguration(config)
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755, uid=os.geteuid())

    for renewal_file in renewal.renewal_conf_files(cli_config):
        try:
            candidate_lineage = storage.RenewableCert(renewal_file, cli_config)
        except (errors.CertStorageError, IOError):
            logger.warning("Renewal conf file %s is broken. Skipping.", renewal_file)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            continue
        # TODO: Handle these differently depending on whether they are
        #       expired or still valid?
        candidate_names = set(candidate_lineage.names())
        if candidate_names == set(domains):
            identical_names_cert = candidate_lineage
        elif candidate_names.issubset(set(domains)):
            # This logic finds and returns the largest subset-names cert
            # in the case where there are several available.
            if subset_names_cert is None:
                subset_names_cert = candidate_lineage
            elif len(candidate_names) > len(subset_names_cert.names()):
                subset_names_cert = candidate_lineage

    return identical_names_cert, subset_names_cert
Beispiel #5
0
def _search_lineages(cli_config, func, initial_rv, *args):
    """Iterate func over unbroken lineages, allowing custom return conditions.

    Allows flexible customization of return values, including multiple
    return values and complex checks.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments
    :param function func: function used while searching over lineages
    :param initial_rv: initial return value of the function (any type)

    :returns: Whatever was specified by `func` if a match is found.
    """
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755, uid=misc.os_geteuid())

    rv = initial_rv
    for renewal_file in storage.renewal_conf_files(cli_config):
        try:
            candidate_lineage = storage.RenewableCert(renewal_file, cli_config)
        except (errors.CertStorageError, IOError):
            logger.debug("Renewal conf file %s is broken. Skipping.", renewal_file)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            continue
        rv = func(candidate_lineage, rv, *args)
    return rv
Beispiel #6
0
    def _get_cp_dir(self, temporary):
        """Return the proper reverter directory."""
        if temporary:
            cp_dir = self.config.temp_checkpoint_dir
        else:
            cp_dir = self.config.in_progress_dir

        util.make_or_verify_dir(cp_dir, constants.CONFIG_DIRS_MODE, os.geteuid(), self.config.strict_permissions)

        return cp_dir
Beispiel #7
0
def lineage_for_certname(cli_config, certname):
    """Find a lineage object with name certname."""
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755, uid=os.geteuid())
    renewal_file = storage.renewal_file_for_certname(cli_config, certname)
    try:
        return storage.RenewableCert(renewal_file, cli_config)
    except (errors.CertStorageError, IOError):
        logger.debug("Renewal conf file %s is broken.", renewal_file)
        logger.debug("Traceback was:\n%s", traceback.format_exc())
        return None
Beispiel #8
0
 def save(self, account):
     account_dir_path = self._account_dir_path(account.id)
     util.make_or_verify_dir(account_dir_path, 0o700, os.geteuid(),
                                self.config.strict_permissions)
     try:
         with open(self._regr_path(account_dir_path), "w") as regr_file:
             regr_file.write(account.regr.json_dumps())
         with util.safe_open(self._key_path(account_dir_path),
                                "w", chmod=0o400) as key_file:
             key_file.write(account.key.json_dumps())
         with open(self._metadata_path(account_dir_path), "w") as metadata_file:
             metadata_file.write(account.meta.json_dumps())
     except IOError as error:
         raise errors.AccountStorageError(error)
Beispiel #9
0
    def save_certificate(self, certr, chain_cert,
                         cert_path, chain_path, fullchain_path):
        """Saves the certificate received from the ACME server.

        :param certr: ACME "certificate" resource.
        :type certr: :class:`acme.messages.Certificate`

        :param list chain_cert:
        :param str cert_path: Candidate path to a certificate.
        :param str chain_path: Candidate path to a certificate chain.
        :param str fullchain_path: Candidate path to a full cert chain.

        :returns: cert_path, chain_path, and fullchain_path as absolute
            paths to the actual files
        :rtype: `tuple` of `str`

        :raises IOError: If unable to find room to write the cert files

        """
        for path in cert_path, chain_path, fullchain_path:
            util.make_or_verify_dir(
                os.path.dirname(path), 0o755, os.geteuid(),
                self.config.strict_permissions)

        cert_pem = OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped)

        cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path)

        try:
            cert_file.write(cert_pem)
        finally:
            cert_file.close()
        logger.info("Server issued certificate; certificate written to %s",
                    abs_cert_path)

        if not chain_cert:
            return abs_cert_path, None, None
        else:
            chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert)

            chain_file, abs_chain_path =\
                    _open_pem_file('chain_path', chain_path)
            fullchain_file, abs_fullchain_path =\
                    _open_pem_file('fullchain_path', fullchain_path)

            _save_chain(chain_pem, chain_file)
            _save_chain(cert_pem + chain_pem, fullchain_file)

            return abs_cert_path, abs_chain_path, abs_fullchain_path
Beispiel #10
0
def make_or_verify_core_dir(directory, mode, uid, strict):
    """Make sure directory exists with proper permissions.

    :param str directory: Path to a directory.
    :param int mode: Directory mode.
    :param int uid: Directory owner.
    :param bool strict: require directory to be owned by current user

    :raises .errors.Error: if the directory cannot be made or verified

    """
    try:
        util.make_or_verify_dir(directory, mode, uid, strict)
    except OSError as error:
        raise errors.Error(_PERM_ERR_FMT.format(error))
Beispiel #11
0
def main(cli_args=sys.argv[1:]):
    """Command line argument parsing and main script execution."""
    sys.excepthook = functools.partial(_handle_exception, config=None)
    plugins = plugins_disco.PluginsRegistry.find_all()

    # note: arg parser internally handles --help (and exits afterwards)
    args = cli.prepare_and_parse_args(plugins, cli_args)
    config = configuration.NamespaceConfig(args)
    zope.component.provideUtility(config)

    # Setup logging ASAP, otherwise "No handlers could be found for
    # logger ..." TODO: this should be done before plugins discovery
    for directory in config.config_dir, config.work_dir:
        util.make_or_verify_dir(
            directory, constants.CONFIG_DIRS_MODE, os.geteuid(),
            "--strict-permissions" in cli_args)
    # TODO: logs might contain sensitive data such as contents of the
    # private key! #525
    util.make_or_verify_dir(
        config.logs_dir, 0o700, os.geteuid(), "--strict-permissions" in cli_args)
    setup_logging(config, _cli_log_handler, logfile='letsencrypt.log')
    cli.possible_deprecation_warning(config)

    logger.debug("certbot version: %s", certbot.__version__)
    # do not log `config`, as it contains sensitive data (e.g. revoke --key)!
    logger.debug("Arguments: %r", cli_args)
    logger.debug("Discovered plugins: %r", plugins)

    sys.excepthook = functools.partial(_handle_exception, config=config)

    # Displayer
    if config.quiet:
        config.noninteractive_mode = True
        displayer = display_util.NoninteractiveDisplay(open(os.devnull, "w"))
    elif config.noninteractive_mode:
        displayer = display_util.NoninteractiveDisplay(sys.stdout)
    elif config.text_mode:
        displayer = display_util.FileDisplay(sys.stdout)
    else:
        displayer = display_util.NcursesDisplay()
    zope.component.provideUtility(displayer)

    # Reporter
    report = reporter.Reporter(config)
    zope.component.provideUtility(report)
    atexit.register(report.atexit_print_messages)

    return config.func(config, plugins)
Beispiel #12
0
    def _add_to_checkpoint_dir(self, cp_dir, save_files, save_notes):
        """Add save files to checkpoint directory.

        :param str cp_dir: Checkpoint directory filepath
        :param set save_files: set of files to save
        :param str save_notes: notes about changes made during the save

        :raises IOError: if unable to open cp_dir + FILEPATHS file
        :raises .ReverterError: if unable to add checkpoint

        """
        util.make_or_verify_dir(
            cp_dir, constants.CONFIG_DIRS_MODE, os.geteuid(),
            self.config.strict_permissions)

        op_fd, existing_filepaths = self._read_and_append(
            os.path.join(cp_dir, "FILEPATHS"))

        idx = len(existing_filepaths)

        for filename in save_files:
            # No need to copy/index already existing files
            # The oldest copy already exists in the directory...
            if filename not in existing_filepaths:
                # Tag files with index so multiple files can
                # have the same filename
                logger.debug("Creating backup of %s", filename)
                try:
                    shutil.copy2(filename, os.path.join(
                        cp_dir, os.path.basename(filename) + "_" + str(idx)))
                    op_fd.write(filename + os.linesep)
                # http://stackoverflow.com/questions/4726260/effective-use-of-python-shutil-copy2
                except IOError:
                    op_fd.close()
                    logger.error(
                        "Unable to add file %s to checkpoint %s",
                        filename, cp_dir)
                    raise errors.ReverterError(
                        "Unable to add file {0} to checkpoint "
                        "{1}".format(filename, cp_dir))
                idx += 1
        op_fd.close()

        with open(os.path.join(cp_dir, "CHANGES_SINCE"), "a") as notes_fd:
            notes_fd.write(save_notes)
Beispiel #13
0
def _search_lineages(cli_config, func, initial_rv):
    """Iterate func over unbroken lineages, allowing custom return conditions.

    Allows flexible customization of return values, including multiple
    return values and complex checks.
    """
    configs_dir = cli_config.renewal_configs_dir
    # Verify the directory is there
    util.make_or_verify_dir(configs_dir, mode=0o755, uid=os.geteuid())

    rv = initial_rv
    for renewal_file in storage.renewal_conf_files(cli_config):
        try:
            candidate_lineage = storage.RenewableCert(renewal_file, cli_config)
        except (errors.CertStorageError, IOError):
            logger.debug("Renewal conf file %s is broken. Skipping.", renewal_file)
            logger.debug("Traceback was:\n%s", traceback.format_exc())
            continue
        rv = func(candidate_lineage, rv)
    return rv
Beispiel #14
0
    def save_certificate(self, cert_pem, chain_pem,
                         cert_path, chain_path, fullchain_path):
        """Saves the certificate received from the ACME server.

        :param str cert_pem:
        :param str chain_pem:
        :param str cert_path: Candidate path to a certificate.
        :param str chain_path: Candidate path to a certificate chain.
        :param str fullchain_path: Candidate path to a full cert chain.

        :returns: cert_path, chain_path, and fullchain_path as absolute
            paths to the actual files
        :rtype: `tuple` of `str`

        :raises IOError: If unable to find room to write the cert files

        """
        for path in cert_path, chain_path, fullchain_path:
            util.make_or_verify_dir(
                os.path.dirname(path), 0o755, misc.os_geteuid(),
                self.config.strict_permissions)


        cert_file, abs_cert_path = _open_pem_file('cert_path', cert_path)

        try:
            cert_file.write(cert_pem)
        finally:
            cert_file.close()
        logger.info("Server issued certificate; certificate written to %s",
                    abs_cert_path)

        chain_file, abs_chain_path =\
                _open_pem_file('chain_path', chain_path)
        fullchain_file, abs_fullchain_path =\
                _open_pem_file('fullchain_path', fullchain_path)

        _save_chain(chain_pem, chain_file)
        _save_chain(cert_pem + chain_pem, fullchain_file)

        return abs_cert_path, abs_chain_path, abs_fullchain_path
Beispiel #15
0
def make_or_verify_needed_dirs(config):
    """Create or verify existence of config, work, and hook directories.

    :param config: Configuration object
    :type config: interfaces.IConfig

    :returns: `None`
    :rtype: None

    """
    util.set_up_core_dir(config.config_dir, constants.CONFIG_DIRS_MODE,
                         compat.os_geteuid(), config.strict_permissions)
    util.set_up_core_dir(config.work_dir, constants.CONFIG_DIRS_MODE,
                         compat.os_geteuid(), config.strict_permissions)

    hook_dirs = (config.renewal_pre_hooks_dir,
                 config.renewal_deploy_hooks_dir,
                 config.renewal_post_hooks_dir,)
    for hook_dir in hook_dirs:
        util.make_or_verify_dir(hook_dir,
                                uid=compat.os_geteuid(),
                                strict=config.strict_permissions)
Beispiel #16
0
 def _save(self, account, acme, regr_only):
     account_dir_path = self._account_dir_path(account.id)
     util.make_or_verify_dir(account_dir_path, 0o700, os.geteuid(),
                             self.config.strict_permissions)
     try:
         with open(self._regr_path(account_dir_path), "w") as regr_file:
             regr = account.regr
             with_uri = RegistrationResourceWithNewAuthzrURI(
                 new_authzr_uri=acme.directory.new_authz,
                 body=regr.body,
                 uri=regr.uri,
                 terms_of_service=regr.terms_of_service)
             regr_file.write(with_uri.json_dumps())
         if not regr_only:
             with util.safe_open(self._key_path(account_dir_path),
                                 "w", chmod=0o400) as key_file:
                 key_file.write(account.key.json_dumps())
             with open(self._metadata_path(
                     account_dir_path), "w") as metadata_file:
                 metadata_file.write(account.meta.json_dumps())
     except IOError as error:
         raise errors.AccountStorageError(error)
Beispiel #17
0
    def _verify_setup(self):
        """Verify the setup to ensure safe operating environment.

        Make sure that files/directories are setup with appropriate permissions
        Aim for defensive coding... make sure all input files
        have permissions of root.

        """
        uid = os.geteuid()
        util.make_or_verify_dir(self.config.work_dir, core_constants.CONFIG_DIRS_MODE, uid)
        util.make_or_verify_dir(self.config.backup_dir, core_constants.CONFIG_DIRS_MODE, uid)
        util.make_or_verify_dir(self.config.config_dir, core_constants.CONFIG_DIRS_MODE, uid)
Beispiel #18
0
 def __init__(self, config):
     self.config = config
     util.make_or_verify_dir(config.accounts_dir, 0o700,
                             self.config.strict_permissions)
Beispiel #19
0
    def __init__(self, config):
        self.config = config

        util.make_or_verify_dir(
            config.backup_dir, constants.CONFIG_DIRS_MODE, os.geteuid(),
            self.config.strict_permissions)
Beispiel #20
0
 def _call(self, directory, mode):
     from certbot.util import make_or_verify_dir
     return make_or_verify_dir(directory, mode, self.uid, strict=True)
Beispiel #21
0
 def _prepare(self, account):
     # type: (Account) -> str
     account_dir_path = self._account_dir_path(account.id)
     util.make_or_verify_dir(account_dir_path, 0o700,
                             self.config.strict_permissions)
     return account_dir_path
Beispiel #22
0
 def __init__(self, config):
     self.config = config
     util.make_or_verify_dir(config.accounts_dir, 0o700, misc.os_geteuid(),
                             self.config.strict_permissions)
Beispiel #23
0
    def __init__(self, config):
        self.config = config

        util.make_or_verify_dir(config.backup_dir, constants.CONFIG_DIRS_MODE,
                                self.config.strict_permissions)
Beispiel #24
0
 def _call(self, directory, mode):
     from certbot.util import make_or_verify_dir
     return make_or_verify_dir(directory, mode, self.uid, strict=True)
Beispiel #25
0
 def __init__(self, config: configuration.NamespaceConfig) -> None:
     self.config = config
     util.make_or_verify_dir(config.accounts_dir, 0o700,
                             self.config.strict_permissions)