Exemple #1
0
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 load_teos_id(teos_pk_path):
    """
    Loads the tower id from disk.

    Args:
        teos_pk_path (:obj:`str`): path to the tower's public key file.

    Returns:
        :obj:`str`: The tower id.

    Raises:
        :obj:`InvalidKey`: if the public key is invalid or cannot be loaded.
    """

    if not teos_pk_path:
        raise InvalidKey(
            "TEOS's public key file not found. Have you registered with the tower?"
        )

    try:
        teos_id = Cryptographer.get_compressed_pk(
            PublicKey(Cryptographer.load_key_file(teos_pk_path)))

    except (InvalidParameter, InvalidKey, ValueError):
        raise InvalidKey(
            "TEOS public key cannot be loaded. Try registering again")

    return teos_id
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
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
def test_load_key_file():
    dummy_sk = ec.generate_private_key(ec.SECP256K1, default_backend())
    dummy_sk_der = dummy_sk.private_bytes(
        encoding=serialization.Encoding.DER,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption(),
    )

    # If file exists and has data in it, function should work.
    with open("key_test_file", "wb") as f:
        f.write(dummy_sk_der)

    appt_data = Cryptographer.load_key_file("key_test_file")
    assert appt_data

    os.remove("key_test_file")

    # If file doesn't exist, function should return None
    assert Cryptographer.load_key_file("nonexistent_file") is None

    # If something that's not a file_path is passed as parameter the method should also return None
    assert Cryptographer.load_key_file(
        0) is None and Cryptographer.load_key_file(None) is None
Exemple #7
0
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 test_load_key_file():
    dummy_sk = PrivateKey()
    dummy_sk_der = dummy_sk.to_der()

    # If file exists and has data in it, function should work.
    with open("key_test_file", "wb") as f:
        f.write(dummy_sk_der)

    Cryptographer.load_key_file("key_test_file")
    os.remove("key_test_file")

    # If file doesn't exist, function should return None
    with pytest.raises(InvalidParameter, match="file not found"):
        Cryptographer.load_key_file("nonexistent_file")

    with pytest.raises(InvalidParameter, match="file path was expected"):
        Cryptographer.load_key_file(0)

    with pytest.raises(InvalidParameter, match="file path was expected"):
        Cryptographer.load_key_file(None)
Exemple #9
0
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 test_load_key_file():
    dummy_sk = ec.generate_private_key(ec.SECP256K1, default_backend())
    dummy_sk_der = dummy_sk.private_bytes(
        encoding=serialization.Encoding.DER,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption(),
    )

    # If file exists and has data in it, function should work.
    with open("key_test_file", "wb") as f:
        f.write(dummy_sk_der)

    Cryptographer.load_key_file("key_test_file")
    os.remove("key_test_file")

    # If file doesn't exist, function should return None
    with pytest.raises(InvalidParameter, match="file not found"):
        Cryptographer.load_key_file("nonexistent_file")

    with pytest.raises(InvalidParameter, match="file path was expected"):
        Cryptographer.load_key_file(0)

    with pytest.raises(InvalidParameter, match="file path was expected"):
        Cryptographer.load_key_file(None)
Exemple #11
0
def main(command_line_conf):
    global db_manager, chain_monitor

    signal(SIGINT, handle_signals)
    signal(SIGTERM, handle_signals)
    signal(SIGQUIT, handle_signals)

    # Loads config and sets up the data folder and log file
    config_loader = ConfigLoader(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF,
                                 command_line_conf)
    config = config_loader.build_config()
    setup_data_folder(DATA_DIR)
    setup_logging(config.get("LOG_FILE"), LOG_PREFIX)

    logger.info("Starting TEOS")
    db_manager = DBManager(config.get("DB_PATH"))

    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("FEED")
    }

    if not can_connect_to_bitcoind(bitcoind_connect_params):
        logger.error("Can't 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:
        try:
            secret_key_der = Cryptographer.load_key_file(
                config.get("TEOS_SECRET_KEY"))
            if not secret_key_der:
                raise IOError("TEOS private key can't be loaded")

            block_processor = BlockProcessor(bitcoind_connect_params)
            carrier = Carrier(bitcoind_connect_params)

            responder = Responder(db_manager, carrier, block_processor)
            watcher = Watcher(
                db_manager,
                block_processor,
                responder,
                secret_key_der,
                config.get("MAX_APPOINTMENTS"),
                config.get("EXPIRY_DELTA"),
            )

            # 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()
            API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")),
                watcher).start()
        except Exception as e:
            logger.error("An error occurred: {}. Shutting down".format(e))
            exit(1)