def test_load_private_key_der(): # load_private_key_der expects a byte encoded data. Any other should fail and return None for wtype in WRONG_TYPES: assert Cryptographer.load_private_key_der(wtype) is None # On the other hand, any random formatter byte array would also fail (zeros for example) assert Cryptographer.load_private_key_der(bytes(32)) is None # A proper formatted key should load sk_der = generate_keypair()[0].to_der() assert Cryptographer.load_private_key_der(sk_der) is not None
def load_keys(user_sk_path): """ Loads all the user private key and id. Args: user_sk_path (:obj:`str`): path to the user's private key file. Returns: :obj:`tuple`: A tuple containing a :obj:`PrivateKey` and a :obj:`str` representing the user sk and user id (compressed pk) respectively. Raises: :obj:`InvalidKey`: if any of the keys is invalid or cannot be loaded. """ if not user_sk_path: raise InvalidKey( "Client's private key file not found. Please check your settings") try: user_sk_der = Cryptographer.load_key_file(user_sk_path) user_sk = Cryptographer.load_private_key_der(user_sk_der) except (InvalidParameter, InvalidKey): raise InvalidKey("Client private key is invalid or cannot be parsed") try: user_id = Cryptographer.get_compressed_pk(user_sk.public_key) except (InvalidParameter, InvalidKey): raise InvalidKey("Client public key cannot be loaded") return user_sk, user_id
def load_keys(data_dir): """ Loads a the client key pair. Args: data_dir (:obj:`str`): path to data directory where the keys are stored. Returns: :obj:`tuple`: a tuple containing a ``PrivateKey`` and a ``str`` representing the client sk and compressed pk respectively. Raises: :obj:`InvalidKey <cli.exceptions.InvalidKey>`: if any of the keys is invalid or cannot be loaded. """ if not isinstance(data_dir, str): raise ValueError("Invalid data_dir. Please check your settings") sk_file_path = os.path.join(data_dir, "sk.der") cli_sk_der = Cryptographer.load_key_file(sk_file_path) cli_sk = Cryptographer.load_private_key_der(cli_sk_der) if cli_sk is None: raise InvalidKey("Client private key is invalid or cannot be parsed") compressed_cli_pk = Cryptographer.get_compressed_pk(cli_sk.public_key) if compressed_cli_pk is None: raise InvalidKey("Client public key cannot be loaded") return cli_sk, compressed_cli_pk
def __init__(self, db_manager, block_processor, responder, sk_der, max_appointments, expiry_delta): self.appointments = dict() self.locator_uuid_map = dict() self.block_queue = Queue() self.db_manager = db_manager self.block_processor = block_processor self.responder = responder self.max_appointments = max_appointments self.expiry_delta = expiry_delta self.signing_key = Cryptographer.load_private_key_der(sk_der)
def load_keys(teos_pk_path, cli_sk_path, cli_pk_path): """ Loads all the keys required so sign, send, and verify the appointment. Args: teos_pk_path (:obj:`str`): path to the TEOS public key file. cli_sk_path (:obj:`str`): path to the client private key file. cli_pk_path (:obj:`str`): path to the client public key file. Returns: :obj:`tuple` or ``None``: a three item tuple containing a teos_pk object, cli_sk object and the cli_sk_der encoded key if all keys can be loaded. ``None`` otherwise. """ if teos_pk_path is None: logger.error( "TEOS's public key file not found. Please check your settings") return None if cli_sk_path is None: logger.error( "Client's private key file not found. Please check your settings") return None if cli_pk_path is None: logger.error( "Client's public key file not found. Please check your settings") return None try: teos_pk_der = Cryptographer.load_key_file(teos_pk_path) teos_pk = PublicKey(teos_pk_der) except ValueError: logger.error("TEOS public key is invalid or cannot be parsed") return None cli_sk_der = Cryptographer.load_key_file(cli_sk_path) cli_sk = Cryptographer.load_private_key_der(cli_sk_der) if cli_sk is None: logger.error("Client private key is invalid or cannot be parsed") return None try: cli_pk_der = Cryptographer.load_key_file(cli_pk_path) PublicKey(cli_pk_der) except ValueError: logger.error("Client public key is invalid or cannot be parsed") return None return teos_pk, cli_sk, cli_pk_der
def __init__(self, db_manager, gatekeeper, block_processor, responder, sk_der, max_appointments, blocks_in_cache): self.appointments = dict() self.locator_uuid_map = dict() self.block_queue = Queue() self.db_manager = db_manager self.gatekeeper = gatekeeper self.block_processor = block_processor self.responder = responder self.max_appointments = max_appointments self.signing_key = Cryptographer.load_private_key_der(sk_der) self.last_known_block = db_manager.load_last_block_hash_watcher() self.locator_cache = LocatorCache(blocks_in_cache)
def main(config): setup_data_folder(config.get("DATA_DIR")) logging_server_ready = multiprocessing.Event() stop_logging_server = multiprocessing.Event() logging_port = multiprocessing.Value("i") logging_process = multiprocessing.Process( target=serve_logging, daemon=True, args=(config.get("LOG_FILE"), logging_port, config.get("DAEMON"), logging_server_ready, stop_logging_server), ) logging_process.start() logging_server_ready.wait() setup_logging(logging_port.value) logger = get_logger(component="Daemon") if not os.path.exists( config.get("TEOS_SECRET_KEY")) or config.get("OVERWRITE_KEY"): logger.info("Generating a new key pair") sk = Cryptographer.generate_key() Cryptographer.save_key_file(sk.to_der(), "teos_sk", config.get("DATA_DIR")) else: logger.info("Tower identity found. Loading keys") secret_key_der = Cryptographer.load_key_file( config.get("TEOS_SECRET_KEY")) if not secret_key_der: raise IOError("TEOS private key cannot be loaded") sk = Cryptographer.load_private_key_der(secret_key_der) # Windows cannot run gunicorn if os.name == "nt" and config.get("WSGI") == "gunicorn": logger.warning( "Windows cannot run gunicorn as WSGI. Changing to waitress") config["WSGI"] = "waitress" try: TeosDaemon(config, sk, logger, logging_port.value, stop_logging_server, logging_process).start() except Exception as e: logger.error("An error occurred: {}. Shutting down".format(e)) stop_logging_server.set() logging_process.join() exit(1)
def load_keys(teos_pk_path, user_sk_path): """ Loads all the keys required so sign, send, and verify the appointment. Args: teos_pk_path (:obj:`str`): path to the tower's public key file. user_sk_path (:obj:`str`): path to the user's private key file. Returns: :obj:`tuple`: a three-item tuple containing a ``str``, a ``PrivateKey`` and a ``str`` representing the tower id (compressed pk), user sk and user id (compressed pk) respectively. Raises: :obj:`InvalidKey <cli.exceptions.InvalidKey>`: if any of the keys is invalid or cannot be loaded. """ if not teos_pk_path: raise InvalidKey( "TEOS's public key file not found. Please check your settings") if not user_sk_path: raise InvalidKey( "Client's private key file not found. Please check your settings") try: teos_pk_der = Cryptographer.load_key_file(teos_pk_path) teos_id = Cryptographer.get_compressed_pk(PublicKey(teos_pk_der)) except (InvalidParameter, InvalidKey, ValueError): raise InvalidKey("TEOS public key cannot be loaded") try: user_sk_der = Cryptographer.load_key_file(user_sk_path) user_sk = Cryptographer.load_private_key_der(user_sk_der) except (InvalidParameter, InvalidKey): raise InvalidKey("Client private key is invalid or cannot be parsed") try: user_id = Cryptographer.get_compressed_pk(user_sk.public_key) except (InvalidParameter, InvalidKey): raise InvalidKey("Client public key cannot be loaded") return teos_id, user_sk, user_id
def test_load_private_key_der(): # load_private_key_der expects a byte encoded data. Any other should fail and return None for wtype in WRONG_TYPES: with pytest.raises(InvalidKey, match="(wrong type)"): Cryptographer.load_private_key_der(wtype) # On the other hand, any random formatter byte array would also fail (zeros for example) with pytest.raises(InvalidKey, match="(wrong size or format)"): Cryptographer.load_private_key_der(bytes(32)) # A proper formatted key should load sk_der = generate_keypair()[0].to_der() Cryptographer.load_private_key_der(sk_der)
def run_teosd(): sk_file_path = os.path.join(config.get("DATA_DIR"), "teos_sk.der") if not os.path.exists(sk_file_path): # Generating teos sk so we can return the teos_id teos_sk = Cryptographer.generate_key() Cryptographer.save_key_file(teos_sk.to_der(), "teos_sk", config.get("DATA_DIR")) else: teos_sk = Cryptographer.load_private_key_der(Cryptographer.load_key_file(sk_file_path)) teos_id = Cryptographer.get_compressed_pk(teos_sk.public_key) # Change the default WSGI for Windows if os.name == "nt": config["WSGI"] = "waitress" teosd_process = Process(target=main, kwargs={"config": config}) teosd_process.start() # Give it some time to bootstrap # TODO: we should do better synchronization using an Event sleep(3) return teosd_process, teos_id
def main(command_line_conf): global db_manager, chain_monitor try: signal(SIGINT, handle_signals) signal(SIGTERM, handle_signals) signal(SIGQUIT, handle_signals) # Loads config and sets up the data folder and log file data_dir = command_line_conf.pop( "DATA_DIR") if "DATA_DIR" in command_line_conf else DATA_DIR config_loader = ConfigLoader(data_dir, CONF_FILE_NAME, DEFAULT_CONF, command_line_conf) config = config_loader.build_config() # Set default RPC port if not overwritten by the user. if "BTC_RPC_PORT" not in config_loader.overwritten_fields: config["BTC_RPC_PORT"] = get_default_rpc_port( config.get("BTC_NETWORK")) setup_data_folder(data_dir) setup_logging(config.get("LOG_FILE"), LOG_PREFIX) logger.info("Starting TEOS") bitcoind_connect_params = { k: v for k, v in config.items() if k.startswith("BTC") } bitcoind_feed_params = { k: v for k, v in config.items() if k.startswith("BTC_FEED") } if not can_connect_to_bitcoind(bitcoind_connect_params): logger.error("Cannot connect to bitcoind. Shutting down") elif not in_correct_network(bitcoind_connect_params, config.get("BTC_NETWORK")): logger.error( "bitcoind is running on a different network, check conf.py and bitcoin.conf. Shutting down" ) else: secret_key_der = Cryptographer.load_key_file( config.get("TEOS_SECRET_KEY")) if not secret_key_der: raise IOError("TEOS private key cannot be loaded") logger.info("tower_id = {}".format( Cryptographer.get_compressed_pk( Cryptographer.load_private_key_der( secret_key_der).public_key))) block_processor = BlockProcessor(bitcoind_connect_params) carrier = Carrier(bitcoind_connect_params) gatekeeper = Gatekeeper( UsersDBM(config.get("USERS_DB_PATH")), block_processor, config.get("SUBSCRIPTION_SLOTS"), config.get("SUBSCRIPTION_DURATION"), config.get("EXPIRY_DELTA"), ) db_manager = AppointmentsDBM(config.get("APPOINTMENTS_DB_PATH")) responder = Responder(db_manager, gatekeeper, carrier, block_processor) watcher = Watcher( db_manager, gatekeeper, block_processor, responder, secret_key_der, config.get("MAX_APPOINTMENTS"), config.get("LOCATOR_CACHE_SIZE"), ) # Create the chain monitor and start monitoring the chain chain_monitor = ChainMonitor(watcher.block_queue, watcher.responder.block_queue, block_processor, bitcoind_feed_params) watcher_appointments_data = db_manager.load_watcher_appointments() responder_trackers_data = db_manager.load_responder_trackers() if len(watcher_appointments_data) == 0 and len( responder_trackers_data) == 0: logger.info("Fresh bootstrap") watcher.awake() watcher.responder.awake() else: logger.info("Bootstrapping from backed up data") # Update the Watcher backed up data if found. if len(watcher_appointments_data) != 0: watcher.appointments, watcher.locator_uuid_map = Builder.build_appointments( watcher_appointments_data) # Update the Responder with backed up data if found. if len(responder_trackers_data) != 0: watcher.responder.trackers, watcher.responder.tx_tracker_map = Builder.build_trackers( responder_trackers_data) # Awaking components so the states can be updated. watcher.awake() watcher.responder.awake() last_block_watcher = db_manager.load_last_block_hash_watcher() last_block_responder = db_manager.load_last_block_hash_responder( ) # Populate the block queues with data if they've missed some while offline. If the blocks of both match # we don't perform the search twice. # FIXME: 32-reorgs-offline dropped txs are not used at this point. last_common_ancestor_watcher, dropped_txs_watcher = block_processor.find_last_common_ancestor( last_block_watcher) missed_blocks_watcher = block_processor.get_missed_blocks( last_common_ancestor_watcher) if last_block_watcher == last_block_responder: dropped_txs_responder = dropped_txs_watcher missed_blocks_responder = missed_blocks_watcher else: last_common_ancestor_responder, dropped_txs_responder = block_processor.find_last_common_ancestor( last_block_responder) missed_blocks_responder = block_processor.get_missed_blocks( last_common_ancestor_responder) # If only one of the instances needs to be updated, it can be done separately. if len(missed_blocks_watcher ) == 0 and len(missed_blocks_responder) != 0: Builder.populate_block_queue(watcher.responder.block_queue, missed_blocks_responder) watcher.responder.block_queue.join() elif len(missed_blocks_responder ) == 0 and len(missed_blocks_watcher) != 0: Builder.populate_block_queue(watcher.block_queue, missed_blocks_watcher) watcher.block_queue.join() # Otherwise they need to be updated at the same time, block by block elif len(missed_blocks_responder) != 0 and len( missed_blocks_watcher) != 0: Builder.update_states(watcher, missed_blocks_watcher, missed_blocks_responder) # Fire the API and the ChainMonitor # FIXME: 92-block-data-during-bootstrap-db chain_monitor.monitor_chain() inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")) API(config.get("API_BIND"), config.get("API_PORT"), inspector, watcher).start() except Exception as e: logger.error("An error occurred: {}. Shutting down".format(e)) exit(1)