def register_file_creation(self, temporary, *files): """Register the creation of all files during letsencrypt execution. Call this method before writing to the file to make sure that the file will be cleaned up if the program exits unexpectedly. (Before a save occurs) :param bool temporary: If the file creation registry is for a temp or permanent save. :param \*files: file paths (str) to be registered """ if temporary: cp_dir = self.direc["temp"] else: cp_dir = self.direc["progress"] le_util.make_or_verify_dir(cp_dir) try: with open(os.path.join(cp_dir, "NEW_FILES"), 'a') as new_fd: for file_path in files: new_fd.write("%s\n" % file_path) except (IOError, OSError): logging.error("ERROR: Unable to register file creation")
def init_save_key(key_size, key_dir, keyname="key-letsencrypt.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:`letsencrypt.client.le_util.Key` :raises ValueError: If unable to generate the key given key_size. """ try: key_pem = make_key(key_size) except ValueError as err: logging.fatal(str(err)) raise err # Save file le_util.make_or_verify_dir(key_dir, 0o700, os.geteuid()) key_f, key_path = le_util.unique_file( os.path.join(key_dir, keyname), 0o600) key_f.write(key_pem) key_f.close() logging.info("Generating key (%d bits): %s", key_size, key_path) return le_util.Key(key_path, key_pem)
def add_to_checkpoint(self, cp_dir, save_files): """Add save files to checkpoint directory. :param str cp_dir: Checkpoint directory filepath :param set save_files: set of files to save """ le_util.make_or_verify_dir(cp_dir, 0o755, os.geteuid()) existing_filepaths = [] op_fd = None filepaths_path = os.path.join(cp_dir, "FILEPATHS") # Open up FILEPATHS differently depending on if it already exists if os.path.isfile(filepaths_path): op_fd = open(filepaths_path, 'r+') existing_filepaths = op_fd.read().splitlines() else: op_fd = open(filepaths_path, 'w') idx = len(existing_filepaths) for filename in save_files: if filename not in existing_filepaths: # Tag files with index so multiple files can # have the same filename logging.debug("Creating backup of %s", filename) shutil.copy2(filename, os.path.join( cp_dir, os.path.basename(filename) + "_" + str(idx))) op_fd.write(filename + '\n') idx += 1 op_fd.close() with open(os.path.join(cp_dir, "CHANGES_SINCE"), 'a') as notes_fd: notes_fd.write(self.save_notes)
def init_key(key_size, key_dir): """Initializes privkey. Inits key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR is placed into DER format to allow the namedtuple to easily work with the protocol. :param str key_dir: Key save directory. """ try: key_pem = crypto_util.make_key(key_size) except ValueError as err: logging.fatal(str(err)) sys.exit(1) # Save file le_util.make_or_verify_dir(key_dir, 0o700) key_f, key_filename = le_util.unique_file( os.path.join(key_dir, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logging.info("Generating key (%d bits): %s", key_size, key_filename) return le_util.Key(key_filename, key_pem)
def add_to_checkpoint(self, cp_dir, save_files): le_util.make_or_verify_dir(cp_dir, 0755) existing_filepaths = [] op_fd = None # Open up FILEPATHS differently depending on if it already exists if os.path.isfile(cp_dir + "FILEPATHS"): op_fd = open(cp_dir + "FILEPATHS", 'r+') existing_filepaths = op_fd.read().splitlines() else: op_fd = open(cp_dir + "FILEPATHS", 'w') idx = len(existing_filepaths) for filename in save_files: 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) shutil.copy2(filename, cp_dir + os.path.basename(filename) + "_" + str(idx)) op_fd.write(filename + '\n') idx += 1 op_fd.close() with open(cp_dir + "CHANGES_SINCE", 'a') as notes_fd: notes_fd.write(self.save_notes)
def save(self): """Save account to disk.""" le_util.make_or_verify_dir(self.config.accounts_dir, 0o700, os.geteuid()) acc_config = configobj.ConfigObj() acc_config.filename = os.path.join( self.config.accounts_dir, self._get_config_filename(self.email)) acc_config.initial_comment = [ "DO NOT EDIT THIS FILE", "Account information for %s under %s" % (self._get_config_filename(self.email), self.config.server), ] acc_config["key"] = self.key.file acc_config["phone"] = self.phone if self.regr is not None: acc_config["RegistrationResource"] = {} acc_config["RegistrationResource"]["uri"] = self.uri acc_config["RegistrationResource"]["new_authzr_uri"] = ( self.new_authzr_uri) acc_config["RegistrationResource"]["terms_of_service"] = ( self.terms_of_service) regr_dict = self.regr.body.to_json() acc_config["RegistrationResource"]["body"] = regr_dict acc_config.write()
def register_file_creation(self, temporary, *files): """Register the creation of all files during letsencrypt execution. Call this method before writing to the file to make sure that the file will be cleaned up if the program exits unexpectedly. (Before a save occurs) :param bool temporary: If the file creation registry is for a temp or permanent save. :param \*files: file paths (str) to be registered """ if temporary: cp_dir = self.direc["temp"] else: cp_dir = self.direc["progress"] le_util.make_or_verify_dir(cp_dir) try: with open(os.path.join(cp_dir, "NEW_FILES"), 'a') as new_fd: for file_path in files: new_fd.write("%s\n" % file_path) except (IOError, OSError): logging.error("ERROR: Unable to register file creation")
def init_save_csr(privkey, names, cert_dir, csrname="csr-letsencrypt.pem"): """Initialize a CSR with the given private key. :param privkey: Key to include in the CSR :type privkey: :class:`letsencrypt.client.le_util.Key` :param set names: `str` names to include in the CSR :param str cert_dir: Certificate save directory. :returns: CSR :rtype: :class:`letsencrypt.client.le_util.CSR` """ csr_pem, csr_der = make_csr(privkey.pem, names) # Save CSR le_util.make_or_verify_dir(cert_dir, 0o755) csr_f, csr_filename = le_util.unique_file( os.path.join(cert_dir, csrname), 0o644) csr_f.write(csr_pem) csr_f.close() logging.info("Creating CSR: %s", csr_filename) return le_util.CSR(csr_filename, csr_der, "der")
def init_key(key_size, key_dir): """Initializes privkey. Inits key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR is placed into DER format to allow the namedtuple to easily work with the protocol. :param str key_dir: Key save directory. """ try: key_pem = crypto_util.make_key(key_size) except ValueError as err: logging.fatal(str(err)) sys.exit(1) # Save file le_util.make_or_verify_dir(key_dir, 0o700) key_f, key_filename = le_util.unique_file( os.path.join(key_dir, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logging.info("Generating key (%d bits): %s", key_size, key_filename) return le_util.Key(key_filename, key_pem)
def store_cert_key(self, encrypt = False): list_file = CERT_KEY_BACKUP + "LIST" le_util.make_or_verify_dir(CERT_KEY_BACKUP, 0700) idx = 0 if encrypt: logger.error("Unfortunately securely storing the certificates/keys \ is not yet available. Stay tuned for the next update!") return False if os.path.isfile(list_file): with open(list_file, 'r+b') as csvfile: csvreader = csv.reader(csvfile) for r in csvreader: idx = int(r[0]) + 1 csvwriter = csv.writer(csvfile) csvwriter.writerow([str(idx), self.cert_file, self.key_file]) else: with open(list_file, 'wb') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(["0", self.cert_file, self.key_file]) shutil.copy2(self.key_file, CERT_KEY_BACKUP + os.path.basename(self.key_file) + "_" + str(idx)) shutil.copy2(self.cert_file, CERT_KEY_BACKUP + os.path.basename(self.cert_file) + "_" + str(idx))
def register_file_creation(self, temporary, *files): """Register the creation of all files during letsencrypt execution. Call this method before writing to the file to make sure that the file will be cleaned up if the program exits unexpectedly. (Before a save occurs) :param temporary: If the file creation registry is for a temp or permanent save. :type temporary: bool :param *files: file paths to be registered :type *files: str """ if temporary: cp_dir = CONFIG.TEMP_CHECKPOINT_DIR else: cp_dir = CONFIG.IN_PROGRESS_DIR le_util.make_or_verify_dir(cp_dir) try: with open(cp_dir + "NEW_FILES", 'a') as fd: for file_path in files: fd.write("%s\n" % file_path) except: logger.error("ERROR: Unable to register file creation")
def add_to_checkpoint(self, cp_dir, save_files): """Add save files to checkpoint directory. :param cp_dir: Checkpoint directory filepath :type cp_dir: str :param save_files: set of files to save :type save_files: set """ le_util.make_or_verify_dir(cp_dir, 0o755) existing_filepaths = [] op_fd = None # Open up FILEPATHS differently depending on if it already exists if os.path.isfile(cp_dir + "FILEPATHS"): op_fd = open(cp_dir + "FILEPATHS", 'r+') existing_filepaths = op_fd.read().splitlines() else: op_fd = open(cp_dir + "FILEPATHS", 'w') idx = len(existing_filepaths) for filename in save_files: 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) shutil.copy2(filename, cp_dir + os.path.basename(filename) + "_" + str(idx)) op_fd.write(filename + '\n') idx += 1 op_fd.close() with open(cp_dir + "CHANGES_SINCE", 'a') as notes_fd: notes_fd.write(self.save_notes)
def save(self): """Save account to disk.""" le_util.make_or_verify_dir( self.config.accounts_dir, 0o700, os.geteuid()) acc_config = configobj.ConfigObj() acc_config.filename = os.path.join( self.config.accounts_dir, self._get_config_filename(self.email)) acc_config.initial_comment = [ "DO NOT EDIT THIS FILE", "Account information for %s under %s" % ( self._get_config_filename(self.email), self.config.server), ] acc_config["key"] = self.key.file acc_config["phone"] = self.phone if self.regr is not None: acc_config["RegistrationResource"] = {} acc_config["RegistrationResource"]["uri"] = self.uri acc_config["RegistrationResource"]["new_authzr_uri"] = ( self.new_authzr_uri) acc_config["RegistrationResource"]["terms_of_service"] = ( self.terms_of_service) regr_dict = self.regr.body.to_json() acc_config["RegistrationResource"]["body"] = regr_dict acc_config.write()
def get_key_csr_pem(self, csr_return_format='der'): """Return key and CSR, generate if necessary. Returns key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR can optionally be returned in DER format as the CSR cannot be loaded back into M2Crypto. :param csr_return_format: If "der" returned CSR is in DER format, PEM otherwise. :param csr_return_format: str :returns: A pair of `(key, csr)`, where `key` is PEM encoded `str` and `csr` is PEM/DER (depedning on `csr_return_format` encoded `str`. :rtype: tuple """ key_pem = None csr_pem = None if not self.key_file: key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE) # Save file le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700) key_f, self.key_file = le_util.unique_file( os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logger.info("Generating key: %s" % self.key_file) else: try: key_pem = open(self.key_file).read().replace("\r", "") except: logger.fatal("Unable to open key file: %s" % self.key_file) sys.exit(1) if not self.csr_file: csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names) # Save CSR le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755) csr_f, self.csr_file = le_util.unique_file( os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644) csr_f.write(csr_pem) csr_f.close() logger.info("Creating CSR: %s" % self.csr_file) else: try: csr = M2Crypto.X509.load_request(self.csr_file) csr_pem, csr_der = csr.as_pem(), csr.as_der() except: logger.fatal("Unable to open CSR file: %s" % self.csr_file) sys.exit(1) if csr_return_format == 'der': return key_pem, csr_der else: return key_pem, csr_pem
def get_key_csr_pem(self, csr_return_format='der'): """Return key and CSR, generate if necessary. Returns key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR can optionally be returned in DER format as the CSR cannot be loaded back into M2Crypto. :param csr_return_format: If "der" returned CSR is in DER format, PEM otherwise. :param csr_return_format: str :returns: A pair of `(key, csr)`, where `key` is PEM encoded `str` and `csr` is PEM/DER (depedning on `csr_return_format` encoded `str`. :rtype: tuple """ key_pem = None csr_pem = None if not self.key_file: key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE) # Save file le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700) key_f, self.key_file = le_util.unique_file( os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logger.info("Generating key: %s" % self.key_file) else: try: key_pem = open(self.key_file).read().replace("\r", "") except: logger.fatal("Unable to open key file: %s" % self.key_file) sys.exit(1) if not self.csr_file: csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names) # Save CSR le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755) csr_f, self.csr_file = le_util.unique_file( os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644) csr_f.write(csr_pem) csr_f.close() logger.info("Creating CSR: %s" % self.csr_file) else: try: csr = M2Crypto.X509.load_request(self.csr_file) csr_pem, csr_der = csr.as_pem(), csr.as_der() except: logger.fatal("Unable to open CSR file: %s" % self.csr_file) sys.exit(1) if csr_return_format == 'der': return key_pem, csr_der else: return key_pem, csr_pem
def __init__(self, config, key, email=None, phone=None, regr=None): le_util.make_or_verify_dir(config.accounts_dir, 0o700, os.geteuid()) self.key = key self.config = config if email is not None and self.safe_email(email): self.email = email else: self.email = None self.phone = phone self.regr = regr
def store_token(self, domain, token): """Store token for later automatic use. :param str domain: domain associated with the token :param str token: token from authorization """ le_util.make_or_verify_dir(self.token_dir, 0o700, os.geteuid()) with open(os.path.join(self.token_dir, domain), 'w') as token_fd: token_fd.write(str(token))
def store_token(self, domain, token): """Store token for later automatic use. :param str domain: domain associated with the token :param str token: token from authorization """ le_util.make_or_verify_dir(self.token_dir, 0o700, os.geteuid()) with open(os.path.join(self.token_dir, domain), 'w') as token_fd: token_fd.write(str(token))
def __init__(self, installer, config, no_confirm=False): self.network = network.Network(config.server) self.installer = installer self.config = config self.no_confirm = no_confirm le_util.make_or_verify_dir(config.cert_key_backup, 0o700, os.geteuid()) # TODO: Find a better solution for this... self.list_path = os.path.join(config.cert_key_backup, "LIST") # Make sure that the file is available for use for rest of class open(self.list_path, "a").close()
def __init__(self, installer, config, no_confirm=False): self.network = network.Network(config.server) self.installer = installer self.config = config self.no_confirm = no_confirm le_util.make_or_verify_dir(config.cert_key_backup, 0o700, os.geteuid()) # TODO: Find a better solution for this... self.list_path = os.path.join(config.cert_key_backup, "LIST") # Make sure that the file is available for use for rest of class open(self.list_path, "a").close()
def __init__(self, config, key, email=None, phone=None, regr=None): le_util.make_or_verify_dir( config.accounts_dir, 0o700, os.geteuid()) self.key = key self.config = config if email is not None and self.safe_email(email): self.email = email else: self.email = None self.phone = phone self.regr = regr
def store_cert_key(cls, cert_path, key_path, config): """Store certificate key. (Used to allow quick revocation) :param str cert_path: Path to a certificate file. :param str key_path: Path to authorized key for certificate :ivar config: Configuration. :type config: :class:`~letsencrypt.client.interfaces.IConfig` """ list_path = os.path.join(config.cert_key_backup, "LIST") le_util.make_or_verify_dir(config.cert_key_backup, 0o700, os.geteuid()) cls._catalog_files( config.cert_key_backup, cert_path, key_path, list_path)
def store_cert_key(cls, cert_path, key_path, config): """Store certificate key. (Used to allow quick revocation) :param str cert_path: Path to a certificate file. :param str key_path: Path to authorized key for certificate :ivar config: Configuration. :type config: :class:`~letsencrypt.client.interfaces.IConfig` """ list_path = os.path.join(config.cert_key_backup, "LIST") le_util.make_or_verify_dir(config.cert_key_backup, 0o700, os.geteuid()) cls._catalog_files(config.cert_key_backup, cert_path, key_path, list_path)
def register_file_creation(self, temporary, *files): r"""Register the creation of all files during letsencrypt execution. Call this method before writing to the file to make sure that the file will be cleaned up if the program exits unexpectedly. (Before a save occurs) :param bool temporary: If the file creation registry is for a temp or permanent save. :param \*files: file paths (str) to be registered :raises letsencrypt.client.errors.LetsEncryptReverterError: If call does not contain necessary parameters or if the file creation is unable to be registered. """ # Make sure some files are provided... as this is an error # Made this mistake in my initial implementation of apache.dvsni.py if not files: raise errors.LetsEncryptReverterError( "Forgot to provide files to registration call") if temporary: cp_dir = self.config.temp_checkpoint_dir else: cp_dir = self.config.in_progress_dir le_util.make_or_verify_dir( cp_dir, constants.CONFIG_DIRS_MODE, os.geteuid()) # Append all new files (that aren't already registered) new_fd = None try: new_fd, ex_files = self._read_and_append( os.path.join(cp_dir, "NEW_FILES")) for path in files: if path not in ex_files: new_fd.write("{0}{1}".format(path, os.linesep)) except (IOError, OSError): logging.error("Unable to register file creation(s) - %s", files) raise errors.LetsEncryptReverterError( "Unable to register file creation(s) - {0}".format(files)) finally: if new_fd is not None: new_fd.close()
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 letsencrypt.client.errors.LetsEncryptReverterError: If unable to add checkpoint """ le_util.make_or_verify_dir(cp_dir, 0o755, os.geteuid()) 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 logging.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() logging.error("Unable to add file %s to checkpoint %s", filename, cp_dir) raise errors.LetsEncryptReverterError( "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)
def get_key_csr_pem(self, csr_return_format = 'der'): """ Returns key and CSR using provided files or generating new files if necessary. Both will be saved in pem format on the filesystem. The CSR can optionally be returned in DER format as the CSR cannot be loaded back into M2Crypto. """ key_pem = None csr_pem = None if not self.key_file: key_pem = crypto_util.make_key(RSA_KEY_SIZE) # Save file le_util.make_or_verify_dir(KEY_DIR, 0700) key_f, self.key_file = le_util.unique_file( KEY_DIR + "key-letsencrypt.pem", 0600) key_f.write(key_pem) key_f.close() logger.info("Generating key: %s" % self.key_file) else: try: key_pem = open(self.key_file).read().replace("\r", "") except: logger.fatal("Unable to open key file: %s" % self.key_file) sys.exit(1) if not self.csr_file: csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names) # Save CSR le_util.make_or_verify_dir(CERT_DIR, 0755) csr_f, self.csr_file = le_util.unique_file( CERT_DIR + "csr-letsencrypt.pem", 0644) csr_f.write(csr_pem) csr_f.close() logger.info("Creating CSR: %s" % self.csr_file) else: #TODO fix this der situation try: csr_pem = open(self.csr_file).read().replace("\r", "") except: logger.fatal("Unable to open CSR file: %s" % self.csr_file) sys.exit(1) if csr_return_format == 'der': return key_pem, csr_der return key_pem, csr_pem
def store_cert_key(self, cert_file, encrypt=False): """Store certificate key. :param str cert_file: Path to a certificate file. :param bool encrypt: Should the certificate key be encrypted? :returns: True if key file was stored successfully, False otherwise. :rtype: bool """ list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST") le_util.make_or_verify_dir(CONFIG.CERT_KEY_BACKUP, 0o700) idx = 0 if encrypt: logging.error( "Unfortunately securely storing the certificates/" "keys is not yet available. Stay tuned for the " "next update!") return False if os.path.isfile(list_file): with open(list_file, 'r+b') as csvfile: csvreader = csv.reader(csvfile) for row in csvreader: idx = int(row[0]) + 1 csvwriter = csv.writer(csvfile) csvwriter.writerow([str(idx), cert_file, self.privkey.file]) else: with open(list_file, 'wb') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(["0", cert_file, self.privkey.file]) shutil.copy2(self.privkey.file, os.path.join( CONFIG.CERT_KEY_BACKUP, os.path.basename(self.privkey.file) + "_" + str(idx))) shutil.copy2(cert_file, os.path.join( CONFIG.CERT_KEY_BACKUP, os.path.basename(cert_file) + "_" + str(idx))) return True
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 letsencrypt.client.errors.LetsEncryptReverterError: If unable to add checkpoint """ le_util.make_or_verify_dir( cp_dir, constants.CONFIG_DIRS_MODE, os.geteuid()) 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 logging.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() logging.error( "Unable to add file %s to checkpoint %s", filename, cp_dir) raise errors.LetsEncryptReverterError( "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)
def init_csr(privkey, names, cert_dir): """Initialize a CSR with the given private key. :param str cert_dir: Certificate save directory. """ csr_pem, csr_der = crypto_util.make_csr(privkey.pem, names) # Save CSR le_util.make_or_verify_dir(cert_dir, 0o755) csr_f, csr_filename = le_util.unique_file( os.path.join(cert_dir, "csr-letsencrypt.pem"), 0o644) csr_f.write(csr_pem) csr_f.close() logging.info("Creating CSR: %s", csr_filename) return le_util.CSR(csr_filename, csr_der, "der")
def init_csr(privkey, names, cert_dir): """Initialize a CSR with the given private key. :param str cert_dir: Certificate save directory. """ csr_pem, csr_der = crypto_util.make_csr(privkey.pem, names) # Save CSR le_util.make_or_verify_dir(cert_dir, 0o755) csr_f, csr_filename = le_util.unique_file( os.path.join(cert_dir, "csr-letsencrypt.pem"), 0o644) csr_f.write(csr_pem) csr_f.close() logging.info("Creating CSR: %s", csr_filename) return le_util.CSR(csr_filename, csr_der, "der")
def store_cert_key(self, cert_file, encrypt=False): """Store certificate key. (Used to allow quick revocation) :param str cert_file: Path to a certificate file. :param bool encrypt: Should the certificate key be encrypted? :returns: True if key file was stored successfully, False otherwise. :rtype: bool """ list_file = os.path.join(self.config.cert_key_backup, "LIST") le_util.make_or_verify_dir(self.config.cert_key_backup, 0o700) idx = 0 if encrypt: logging.error("Unfortunately securely storing the certificates/" "keys is not yet available. Stay tuned for the " "next update!") return False if os.path.isfile(list_file): with open(list_file, 'r+b') as csvfile: csvreader = csv.reader(csvfile) for row in csvreader: idx = int(row[0]) + 1 csvwriter = csv.writer(csvfile) csvwriter.writerow([str(idx), cert_file, self.authkey.file]) else: with open(list_file, 'wb') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(["0", cert_file, self.authkey.file]) shutil.copy2( self.authkey.file, os.path.join(self.config.cert_key_backup, os.path.basename(self.authkey.file) + "_" + str(idx))) shutil.copy2( cert_file, os.path.join(self.config.cert_key_backup, os.path.basename(cert_file) + "_" + str(idx))) return True
def init_key_csr(self): """Initializes privkey and csr. Inits key and CSR using provided files or generating new files if necessary. Both will be saved in PEM format on the filesystem. The CSR is placed into DER format to allow the namedtuple to easily work with the protocol. """ if not self.privkey.file: key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE) # Save file le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0o700) key_f, key_filename = le_util.unique_file( os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600) key_f.write(key_pem) key_f.close() logger.info("Generating key: %s" % key_filename) self.privkey = Client.Key(key_filename, key_pem) if not self.csr.file: csr_pem, csr_der = crypto_util.make_csr( self.privkey.pem, self.names) # Save CSR le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755) csr_f, csr_filename = le_util.unique_file( os.path.join(CONFIG.CERT_DIR, "csr-letsencrypt.pem"), 0o644) csr_f.write(csr_pem) csr_f.close() logger.info("Creating CSR: %s" % csr_filename) self.csr = Client.CSR(csr_filename, csr_der, "der") elif self.csr.type != "der": # The user is going to pass in a pem format file # That is why we must conver it to der since the # protocol uses der exclusively. csr_obj = M2Crypto.X509.load_request_string(self.csr.data) self.csr = Client.CSR(self.csr.file, csr_obj.as_der(), "der")
def register_file_creation(self, temporary, *files): """ This is used to register the creation of all files during Letsencrypt execution. Call this method before writing to the file to make sure that the file will be cleaned up if the program exits unexpectedly. (Before a save occurs) """ if temporary: cp_dir = TEMP_CHECKPOINT_DIR else: cp_dir = IN_PROGRESS_DIR le_util.make_or_verify_dir(cp_dir) try: with open(cp_dir + "NEW_FILES", 'a') as fd: for f in files: fd.write("%s\n" % f) except: logger.error("ERROR: Unable to register file creation")
def store_cert_key(self, cert_file, encrypt=False): """Store certificate key. :param cert_file: Path to a certificate file. :type cert_file: str :param encrypt: Should the certificate key be encrypted? :type encrypt: bool """ list_file = os.path.join(CONFIG.CERT_KEY_BACKUP, "LIST") le_util.make_or_verify_dir(CONFIG.CERT_KEY_BACKUP, 0o700) idx = 0 if encrypt: logger.error("Unfortunately securely storing the certificates/" "keys is not yet available. Stay tuned for the " "next update!") return False if os.path.isfile(list_file): with open(list_file, 'r+b') as csvfile: csvreader = csv.reader(csvfile) for row in csvreader: idx = int(row[0]) + 1 csvwriter = csv.writer(csvfile) csvwriter.writerow([str(idx), cert_file, self.key_file]) else: with open(list_file, 'wb') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(["0", cert_file, self.key_file]) shutil.copy2( self.key_file, os.path.join(CONFIG.CERT_KEY_BACKUP, os.path.basename(self.key_file) + "_" + str(idx))) shutil.copy2( cert_file, os.path.join(CONFIG.CERT_KEY_BACKUP, os.path.basename(cert_file) + "_" + str(idx)))
def from_email(cls, config, email): """Generate a new account from an email address. :param config: Configuration :type config: :class:`letsencrypt.client.interfaces.IConfig` :param str email: Email address :raises letsencrypt.client.errors.LetsEncryptClientError: If invalid email address is given. """ if not email or cls.safe_email(email): email = email if email else None le_util.make_or_verify_dir(config.account_keys_dir, 0o700, os.geteuid()) key = crypto_util.init_save_key(config.rsa_key_size, config.account_keys_dir, cls._get_config_filename(email)) return cls(config, key, email) raise errors.LetsEncryptClientError("Invalid email address.")
def from_email(cls, config, email): """Generate a new account from an email address. :param config: Configuration :type config: :class:`letsencrypt.client.interfaces.IConfig` :param str email: Email address :raises letsencrypt.client.errors.LetsEncryptClientError: If invalid email address is given. """ if not email or cls.safe_email(email): email = email if email else None le_util.make_or_verify_dir( config.account_keys_dir, 0o700, os.geteuid()) key = crypto_util.init_save_key( config.rsa_key_size, config.account_keys_dir, cls._get_config_filename(email)) return cls(config, key, email) raise errors.LetsEncryptClientError("Invalid email address.")
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() le_util.make_or_verify_dir(self.config.work_dir, 0o755, uid) le_util.make_or_verify_dir(self.config.backup_dir, 0o755, uid) le_util.make_or_verify_dir(self.config.config_dir, 0o755, uid)
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() le_util.make_or_verify_dir(self.config.config_dir, 0o755, uid) le_util.make_or_verify_dir(self.config.work_dir, 0o755, uid) le_util.make_or_verify_dir(self.config.backup_dir, 0o755, uid)
def _call(self, directory, mode): from letsencrypt.client.le_util import make_or_verify_dir return make_or_verify_dir(directory, mode, self.uid)
def _call(self, directory, mode): from letsencrypt.client.le_util import make_or_verify_dir return make_or_verify_dir(directory, mode, self.uid)
def main(): # pylint: disable=too-many-branches, too-many-statements """Command line argument parsing and main script execution.""" # note: arg parser internally handles --help (and exits afterwards) args = create_parser().parse_args() config = configuration.NamespaceConfig(args) # note: check is done after arg parsing as --help should work w/o root also. if not os.geteuid() == 0: sys.exit( "{0}Root is required to run letsencrypt. Please use sudo.{0}" .format(os.linesep)) # Set up logging logger = logging.getLogger() logger.setLevel(logging.INFO) if args.use_curses: logger.addHandler(log.DialogHandler()) displayer = display_util.NcursesDisplay() else: displayer = display_util.FileDisplay(sys.stdout) zope.component.provideUtility(displayer) if args.view_config_changes: client.view_config_changes(config) sys.exit() if args.revoke or args.rev_cert is not None or args.rev_key is not None: # This depends on the renewal config and cannot be completed yet. zope.component.getUtility(interfaces.IDisplay).notification( "Revocation is not available with the new Boulder server yet.") # client.revoke(config, args.no_confirm, args.rev_cert, args.rev_key) sys.exit() if args.rollback > 0: client.rollback(args.rollback, config) sys.exit() le_util.make_or_verify_dir( config.config_dir, constants.CONFIG_DIRS_MODE, os.geteuid()) # Prepare for init of Client if args.email is None: acc = client.determine_account(config) else: try: # The way to get the default would be args.email = "" # First try existing account acc = account.Account.from_existing_account(config, args.email) except errors.LetsEncryptClientError: try: # Try to make an account based on the email address acc = account.Account.from_email(config, args.email) except errors.LetsEncryptClientError: sys.exit(1) if acc is None: sys.exit(0) all_auths = init_auths(config) logging.debug('Initialized authenticators: %s', all_auths.keys()) try: auth = client.determine_authenticator(all_auths, config) logging.debug("Selected authenticator: %s", auth) except errors.LetsEncryptClientError as err: logging.critical(str(err)) sys.exit(1) if auth is None: sys.exit(0) # Use the same object if possible if interfaces.IInstaller.providedBy(auth): # pylint: disable=no-member installer = auth else: # This is simple and avoids confusion right now. installer = None if args.domains is None: doms = display_ops.choose_names(installer) else: doms = args.domains if not doms: sys.exit(0) acme = client.Client(config, acc, auth, installer) # Validate the key and csr client.validate_key_csr(acc.key) # This more closely mimics the capabilities of the CLI # It should be possible for reconfig only, install-only, no-install # I am not sure the best way to handle all of the unimplemented abilities, # but this code should be safe on all environments. cert_file = None if auth is not None: if acc.regr is None: try: acme.register() except errors.LetsEncryptClientError: sys.exit(0) cert_key, cert_file, chain_file = acme.obtain_certificate(doms) if installer is not None and cert_file is not None: acme.deploy_certificate(doms, cert_key, cert_file, chain_file) if installer is not None: acme.enhance_config(doms, args.redirect)
def main(): # pylint: disable=too-many-branches, too-many-statements """Command line argument parsing and main script execution.""" # note: arg parser internally handles --help (and exits afterwards) args = create_parser().parse_args() config = configuration.NamespaceConfig(args) # note: check is done after arg parsing as --help should work w/o root also. if not os.geteuid() == 0: sys.exit( "{0}Root is required to run letsencrypt. Please use sudo.{0}". format(os.linesep)) # Set up logging logger = logging.getLogger() logger.setLevel(logging.INFO) if args.use_curses: logger.addHandler(log.DialogHandler()) displayer = display_util.NcursesDisplay() else: displayer = display_util.FileDisplay(sys.stdout) zope.component.provideUtility(displayer) if args.view_config_changes: client.view_config_changes(config) sys.exit() if args.revoke or args.rev_cert is not None or args.rev_key is not None: # This depends on the renewal config and cannot be completed yet. zope.component.getUtility(interfaces.IDisplay).notification( "Revocation is not available with the new Boulder server yet.") # client.revoke(config, args.no_confirm, args.rev_cert, args.rev_key) sys.exit() if args.rollback > 0: client.rollback(args.rollback, config) sys.exit() le_util.make_or_verify_dir(config.config_dir, constants.CONFIG_DIRS_MODE, os.geteuid()) # Prepare for init of Client if args.email is None: acc = client.determine_account(config) else: try: # The way to get the default would be args.email = "" # First try existing account acc = account.Account.from_existing_account(config, args.email) except errors.LetsEncryptClientError: try: # Try to make an account based on the email address acc = account.Account.from_email(config, args.email) except errors.LetsEncryptClientError: sys.exit(1) if acc is None: sys.exit(0) all_auths = init_auths(config) logging.debug('Initialized authenticators: %s', all_auths.keys()) try: auth = client.determine_authenticator(all_auths, config) logging.debug("Selected authenticator: %s", auth) except errors.LetsEncryptClientError as err: logging.critical(str(err)) sys.exit(1) if auth is None: sys.exit(0) # Use the same object if possible if interfaces.IInstaller.providedBy(auth): # pylint: disable=no-member installer = auth else: # This is simple and avoids confusion right now. installer = None if args.domains is None: doms = display_ops.choose_names(installer) else: doms = args.domains if not doms: sys.exit(0) acme = client.Client(config, acc, auth, installer) # Validate the key and csr client.validate_key_csr(acc.key) # This more closely mimics the capabilities of the CLI # It should be possible for reconfig only, install-only, no-install # I am not sure the best way to handle all of the unimplemented abilities, # but this code should be safe on all environments. cert_file = None if auth is not None: if acc.regr is None: try: acme.register() except errors.LetsEncryptClientError: sys.exit(0) cert_key, cert_file, chain_file = acme.obtain_certificate(doms) if installer is not None and cert_file is not None: acme.deploy_certificate(doms, cert_key, cert_file, chain_file) if installer is not None: acme.enhance_config(doms, args.redirect)