def test_vladimir_cannot_verify_interface_with_ursulas_signing_key(
        mining_ursulas):
    his_target = list(mining_ursulas)[4]

    # Vladimir has his own ether address; he hopes to publish it along with Ursula's details
    # so that Alice (or whomever) pays him instead of Ursula, even though Ursula is providing the service.
    vladimir_ether_address = '0xE57bFE9F44b819898F47BF37E5AF72a0783e1141'

    # Vladimir imitates Ursula - copying her public keys and interface info, but inserting his ether address.
    vladimir = Ursula(crypto_power=his_target._crypto_power,
                      rest_host=his_target.rest_interface.host,
                      rest_port=his_target.rest_interface.port,
                      checksum_address=vladimir_ether_address,
                      interface_signature=his_target._interface_signature,
                      is_me=False)

    # Vladimir can substantiate the stamp using his own ether address...
    vladimir.substantiate_stamp()
    vladimir.stamp_is_valid()

    # ...however, the signature for the interface info isn't valid.
    with pytest.raises(vladimir.InvalidNode):
        vladimir.interface_is_valid()

    # Consequently, the metadata isn't valid.
    with pytest.raises(vladimir.InvalidNode):
        vladimir.validate_metadata()
def test_vladimir_uses_his_own_signing_key(alice, mining_ursulas):
    """
    Similar to the attack above, but this time Vladimir makes his own interface signature
    using his own signing key, which he claims is Ursula's.
    """
    his_target = list(mining_ursulas)[4]
    vladimir_ether_address = '0xE57bFE9F44b819898F47BF37E5AF72a0783e1141'

    fraduluent_keys = CryptoPower(power_ups=Ursula._default_crypto_powerups)

    vladimir = Ursula(crypto_power=fraduluent_keys,
                      rest_host=his_target.rest_interface.host,
                      rest_port=his_target.rest_interface.port,
                      checksum_address=vladimir_ether_address,
                      is_me=False)
    message = vladimir._signable_interface_info_message()
    signature = vladimir._crypto_power.power_ups(SigningPower).sign(message)
    vladimir._interface_signature_object = signature

    vladimir.substantiate_stamp()

    # With this slightly more sophisticated attack, his metadata does appear valid.
    vladimir.validate_metadata()

    # However, the actual handshake proves him wrong.
    with pytest.raises(vladimir.InvalidNode):
        vladimir.verify_node(alice.network_middleware)
Example #3
0
def make_ursulas(how_many_ursulas: int, ursula_starting_port: int,
                 config: NucypherConfig) -> list:
    """
    :param how_many_ursulas: How many Ursulas to create.
    :param ursula_starting_port: The port of the first created Ursula; subsequent Ursulas will increment the port number by 1.
    :return: A list of created Ursulas
    """
    event_loop = asyncio.get_event_loop()

    URSULAS = []
    for _u in range(how_many_ursulas):
        port = ursula_starting_port + _u
        _URSULA = Ursula(
            dht_port=port,
            ip_address="127.0.0.1",
            db_name="test-{}".format(port),
            rest_port=port + 100,
            config=config)  # TODO: Make ports unstupid and more clear.

        class MockDatastoreThreadPool(object):
            def callInThread(self, f, *args, **kwargs):
                return f(*args, **kwargs)

        _URSULA.datastore_threadpool = MockDatastoreThreadPool()
        _URSULA.dht_listen()

        URSULAS.append(_URSULA)

    for _counter, ursula in enumerate(URSULAS):
        event_loop.run_until_complete(
            ursula.server.bootstrap([("127.0.0.1", ursula_starting_port + _c)
                                     for _c in range(how_many_ursulas)]))
        ursula.publish_dht_information()

    return URSULAS
Example #4
0
    def rpc_store(self, sender, nodeid, key, value):
        source = kademlia.node.Node(nodeid, sender[0], sender[1])
        self.welcomeIfNewNode(source)
        self.log.debug("got a store request from %s" % str(sender))

        header, payload = default_constant_splitter(value, return_remainder=True)

        if header == constants.BYTESTRING_IS_URSULA_IFACE_INFO:
            from nucypher.characters import Ursula
            stranger_ursula = Ursula.from_bytes(payload,
                                                federated_only=self.sourceNode.federated_only)  # TODO: Is federated_only the right thing here?

            if stranger_ursula.interface_is_valid() and key == digest(stranger_ursula.canonical_public_address):
                self.sourceNode._node_storage[stranger_ursula.checksum_public_address] = stranger_ursula  # TODO: 340
                return True
            else:
                self.log.warning("Got request to store invalid node: {} / {}".format(key, value))
                self.illegal_keys_seen.append(key)
                return False
        elif header == constants.BYTESTRING_IS_TREASURE_MAP:
            from nucypher.policy.models import TreasureMap
            try:
                treasure_map = TreasureMap.from_bytes(payload)
                self.log.info("Storing TreasureMap: {} / {}".format(key, value))
                self.sourceNode._treasure_maps[treasure_map.public_id()] = value
                return True
            except TreasureMap.InvalidSignature:
                self.log.warning("Got request to store invalid TreasureMap: {} / {}".format(key, value))
                self.illegal_keys_seen.append(key)
                return False
        else:
            self.log.info(
                "Got request to store bad k/v: {} / {}".format(key, value))
            return False
Example #5
0
def read_node_metadata(filepath: str, federated_only=False) -> Ursula:
    """Init one ursula from node storage file"""

    with open(filepath, "r") as seed_file:
        seed_file.seek(0)
        node_bytes = binascii.unhexlify(seed_file.read())

        node = Ursula.from_bytes(node_bytes, federated_only=federated_only)
        return node
Example #6
0
def run_ursula(rest_port, dht_port, db_name, checksum_address, federated_only,
               seed_node, data_dir, config_file) -> None:
    """

    The following procedure is required to "spin-up" an Ursula node.

        1. Collect all known known from storages
        2. Start the asyncio event loop
        3. Initialize Ursula object
        4. Start DHT listener
        5. Enter the learning loop
        6. Run TLS deployment
        7. Start the staking daemon

    Configurable values are first read from the .ini configuration file,
    but can be overridden (mostly for testing purposes) with inline cli options.

    """

    if not seed_node:
        other_nodes = collect_stored_nodes(
            federated_only=federated_only)  # 1. Collect known nodes
    else:
        other_nodes = tuple()

    overrides = dict(federated_only=federated_only,
                     known_nodes=other_nodes,
                     rest_port=rest_port,
                     dht_port=dht_port,
                     db_name=db_name,
                     checksum_address=checksum_address)

    if seed_node:
        seed_overrides = dict(always_be_learning=False,
                              abort_on_learning_error=False)

        overrides.update(seed_overrides)

    asyncio.set_event_loop(asyncio.new_event_loop())  # 2. Init DHT async loop

    # 3. Initialize Ursula (includes overrides)
    ursula = Ursula.from_config(filepath=config_file, overrides=overrides)

    ursula.dht_listen()  # 4. Start DHT

    write_node_metadata(seed_node=seed_node,
                        node=ursula,
                        node_metadata_dir=data_dir)

    if not seed_node:
        ursula.start_learning_loop()  # 5. Enter learning loop

    ursula.get_deployer().run()  # 6. Run TLS Deployer

    if not federated_only:
        ursula.stake()  # 7. start staking daemon
Example #7
0
def get_seed():
    teacher_dht_port = 3500
    teacher_rest_port = int(teacher_dht_port) + 100
    with open("examples-runtime-cruft/node-metadata-{}".format(teacher_rest_port), "r") as f:
        f.seek(0)
        teacher_bytes = binascii.unhexlify(f.read())
    URSULA = Ursula.from_bytes(teacher_bytes, federated_only=True)
    print("Will learn from {}".format(URSULA))

    return URSULA
def test_anybody_can_encrypt():
    """
    Similar to anybody_can_verify() above; we show that anybody can encrypt.
    """
    everyman = Character()
    ursula = Ursula(is_me=False)

    cleartext = b"This is Officer Rod Farva. Come in, Ursula!  Come in Ursula!"

    ciphertext, signature = everyman.encrypt_for(ursula, cleartext, sign=False)

    assert signature == constants.NOT_SIGNED
    assert ciphertext is not None
Example #9
0
def test_alice_can_get_ursulas_keys_via_rest(ursulas):
    mock_client = TestClient(ursulas[0].rest_app)
    response = mock_client.get('http://localhost/public_keys')
    splitter = BytestringSplitter((UmbralPublicKey, PUBLIC_KEY_LENGTH),
                                  (UmbralPublicKey, PUBLIC_KEY_LENGTH))
    signing_key, encrypting_key = splitter(response.content)
    stranger_ursula_from_public_keys = Ursula.from_public_keys({
        SigningPower:
        signing_key,
        EncryptingPower:
        encrypting_key
    })
    assert stranger_ursula_from_public_keys == ursulas[0]
Example #10
0
 def consider_arrangement(self, arrangement):
     ursula = Ursula.from_rest_url(
         self,
         host=arrangement.ursula.rest_interface.host,
         port=arrangement.ursula.rest_interface.port,
         federated_only=True,
     )  # TODO: Make this the Ursula to whom we connect.
     response = requests.post("https://localhost:3601/consider_arrangement",
                              bytes(arrangement),
                              verify=False)
     if response.status_code == 200:
         response.was_accepted = True
     else:
         raise RuntimeError(
             "Something went terribly wrong.  What'd you do?!")
     return response
Example #11
0
 def find_ursula(self, contract=None):
     ursula = Ursula.as_discovered_on_network(
         dht_port=None,
         ip_address="localhost",
         rest_port=3601,
         powers_and_keys={
             SigningPower: self.ursulas[0].stamp.as_umbral_pubkey(),
             EncryptingPower: self.ursulas[0].public_key(EncryptingPower)
         })
     response = requests.post("https://localhost:3601/consider_arrangement",
                              bytes(contract),
                              verify=False)
     if response.status_code == 200:
         response.was_accepted = True
     else:
         raise RuntimeError(
             "Something went terribly wrong.  What'd you do?!")
     return ursula, response
Example #12
0
    def __init__(self,
                 teacher_dht_port: int = 3500,
                 teacher_rest_port: int = 3600,
                 node_meta_dir: str = "../examples/examples-runtime-cruft"):
        self.teacher_dht_port = teacher_dht_port

        if teacher_rest_port:
            self.teacher_rest_port = teacher_rest_port
        else:
            self.teacher_rest_port = int(self.teacher_dht_port) + 100

        with open(
                "{}/node-metadata-{}".format(node_meta_dir,
                                             self.teacher_rest_port),
                "r") as f:
            f.seek(0)
            teacher_bytes = binascii.unhexlify(f.read())

        self.ursula = Ursula.from_bytes(teacher_bytes, federated_only=True)
def spin_up_ursula(dht_port, rest_port, db_name, teachers=()):
    metadata_file = "examples-runtime-cruft/node-metadata-{}".format(rest_port)

    asyncio.set_event_loop(asyncio.new_event_loop()
                           )  # Ugh.  Awful.  But needed until we shed the DHT.
    _URSULA = Ursula(
        dht_port=dht_port,
        rest_port=rest_port,
        rest_host="localhost",
        dht_host="localhost",
        db_name=db_name,
        federated_only=True,
        known_nodes=teachers,
    )
    _URSULA.dht_listen()
    try:
        with open(metadata_file, "w") as f:
            f.write(bytes(_URSULA).hex())
        _URSULA.start_learning_loop()
        _URSULA.get_deployer().run()
    finally:
        os.remove(db_name)
        os.remove(metadata_file)
Example #14
0
def test_alice_refuses_to_make_arrangement_unless_ursula_is_valid(
        blockchain_alice, idle_blockchain_policy, mining_ursulas):
    target = list(mining_ursulas)[2]
    # First, let's imagine that Alice has sampled a Vladimir while making this policy.
    vladimir = Ursula(
        crypto_power=CryptoPower(power_ups=Ursula._default_crypto_powerups),
        rest_host=target.rest_interface.host,
        rest_port=target.rest_interface.port,
        checksum_address=
        '0xE57bFE9F44b819898F47BF37E5AF72a0783e1141',  # Fradulent address
        is_me=False)
    message = vladimir._signable_interface_info_message()
    signature = vladimir._crypto_power.power_ups(SigningPower).sign(message)
    vladimir.substantiate_stamp()
    vladimir._interface_signature_object = signature

    class FakeArrangement:
        federated = False

    with pytest.raises(vladimir.InvalidNode):
        idle_blockchain_policy.consider_arrangement(
            network_middleware=blockchain_alice.network_middleware,
            arrangement=FakeArrangement(),
            ursula=vladimir)
Example #15
0
 def check_node_with_cert(node, cert_file):
     response = requests.get("https://{}/public_information".format(
         node.rest_url()),
                             verify=cert_file)
     ursula = Ursula.from_bytes(response.content, federated_only=True)
     assert ursula == node
def test_ursula_generates_self_signed_cert(nucypher_test_config):
    ursula = Ursula(attach_server=False, config=nucypher_test_config)
    cert, cert_private_key = ursula.generate_self_signed_certificate()
    public_key_numbers = ursula.public_key(
        SigningPower).to_cryptography_pubkey().public_numbers()
    assert cert.public_key().public_numbers() == public_key_numbers
import os

from cryptography.hazmat.primitives.asymmetric import ec

from hendrix.deploy.tls import HendrixDeployTLS
from hendrix.facilities.services import ExistingKeyTLSContextFactory
from nucypher.characters import Ursula
from OpenSSL.crypto import X509
from OpenSSL.SSL import TLSv1_2_METHOD

from nucypher.crypto.api import generate_self_signed_certificate

DB_NAME = "non-mining-proxy-node"

_URSULA = Ursula(dht_port=3501,
                 rest_port=3601,
                 ip_address="localhost",
                 db_name=DB_NAME)
_URSULA.dht_listen()

CURVE = ec.SECP256R1
cert, private_key = generate_self_signed_certificate(
    _URSULA.stamp.fingerprint().decode(), CURVE)

deployer = HendrixDeployTLS("start", {
    "wsgi": _URSULA.rest_app,
    "https_port": _URSULA.rest_port
},
                            key=private_key,
                            cert=X509.from_cryptography(cert),
                            context_factory=ExistingKeyTLSContextFactory,
                            context_factory_kwargs={
Example #18
0
from nucypher.config.metadata import collect_stored_nodes
from nucypher.data_sources import DataSource
# This is already running in another process.
from nucypher.network.middleware import RestMiddleware
>>>>>>> 26103ab... Project-wide automated import optimization, followed-up with some hand-tweaking:examples/finnegans-wake-demo.py

# This is already running in another process.


##############################################
# This is already running in another process.
##############################################

BLOCKCHAIN = Blockchain.connect()

URSULA = Ursula.from_config()

#########
# Alice #
#########

ALICE = Alice.from_config()

# Here are our Policy details.
policy_end_datetime = maya.now() + datetime.timedelta(days=201)
m = 2
n = 3
label = b"secret/files/and/stuff"

# Alice grants to Bob.
BOB = Bob.from_config()
Example #19
0
root.setLevel(logging.DEBUG)

ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.INFO)
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
root.addHandler(ch)

teacher_dht_port = sys.argv[2]
teacher_rest_port = int(teacher_dht_port) + 100
with open("examples-runtime-cruft/node-metadata-{}".format(teacher_rest_port),
          "r") as f:
    f.seek(0)
    teacher_bytes = binascii.unhexlify(f.read())
URSULA = Ursula.from_bytes(teacher_bytes, federated_only=True)
print("Will learn from {}".format(URSULA))

# network_middleware = SandboxRestMiddleware([URSULA])

#########
# Alice #
#########

ALICE = Alice(
    network_middleware=RestMiddleware(),
    known_nodes=(URSULA, ),  # in lieu of seed nodes
    federated_only=True,
    always_be_learning=True)  # TODO: 289

# Here are our Policy details.
Example #20
0
def make_ursulas(ether_addresses: list,
                 miner_agent=None,
                 miners=False,
                 bare=False,
                 know_each_other=True,
                 **ursula_kwargs) -> Set[Ursula]:
    """
    :param ether_addresses: Ethereum addresses to create ursulas with.
    :param ursula_starting_port: The port of the first created Ursula; subsequent Ursulas will increment the port number by 1.


    :param miner_agent: A miner agent instance to use when creating ursulas.
    :param miners: If True, create staking ursulas on the blockchain from the addresses
    :param bare: If True, Create an non-learning Ursula without a rest app, dht server or database attached,
                 for testing mining functionality when network transport is not needed. "Just a miner"

    :return: A list of created Ursulas
    """

    if isinstance(ether_addresses, int):
        ether_addresses = [to_checksum_address(secure_random(20)) for _ in range(ether_addresses)]

    event_loop = asyncio.get_event_loop()
    if not _TEST_KNOWN_URSULAS_CACHE:
        starting_port = constants.URSULA_PORT_SEED
    else:
        starting_port = max(_TEST_KNOWN_URSULAS_CACHE.keys()) + 1

    ursulas = set()
    for port, ether_address in enumerate(ether_addresses, start=starting_port):

        if bare:
            ursula = Ursula(is_me=False,            # do not attach dht server
                            rest_host="localhost",  # TODO: remove rest interface
                            rest_port=port + 100,
                            checksum_address=ether_address,
                            always_be_learning=False,
                            miner_agent=miner_agent,
                            abort_on_learning_error=True,
                            **ursula_kwargs)

            ursula.is_me = True  # Patch to allow execution of transacting methods in tests

        else:
            federated_only = not miners
            if federated_only:
                ether_address = None
            ursula = Ursula(is_me=True,
                            checksum_address=ether_address,
                            dht_host="localhost",
                            dht_port=port,
                            db_name="test-{}".format(port),
                            rest_host="localhost",
                            rest_port=port+100,
                            always_be_learning=False,
                            miner_agent=miner_agent,
                            federated_only=federated_only,
                            **ursula_kwargs)

            ursula.attach_rest_server()

            class MockDatastoreThreadPool(object):
                def callInThread(self, f, *args, **kwargs):
                    return f(*args, **kwargs)

            ursula.datastore_threadpool = MockDatastoreThreadPool()
            ursula.dht_listen()

        if miners is True:
            # TODO: 309
            # stake a random amount
            min_stake, balance = constants.MIN_ALLOWED_LOCKED, ursula.token_balance
            amount = random.randint(min_stake, balance)

            # for a random lock duration
            min_locktime, max_locktime = constants.MIN_LOCKED_PERIODS, constants.MAX_MINTING_PERIODS
            periods = random.randint(min_locktime, max_locktime)

            ursula.initialize_stake(amount=amount, lock_periods=periods)
        else:
            ursula.federated_only = True

        ursulas.add(ursula)
        _TEST_KNOWN_URSULAS_CACHE[ursula.rest_interface.port] = ursula

    if know_each_other and not bare:

        for ursula_to_teach in ursulas:
            # Add other Ursulas as known nodes.
            for ursula_to_learn_about in ursulas:
                ursula_to_teach.remember_node(ursula_to_learn_about)

            event_loop.run_until_complete(
                ursula.dht_server.bootstrap(
                    [("localhost", starting_port + _c) for _c in range(len(ursulas))]))
            ursula.publish_dht_information()

    return ursulas
Example #21
0
# This is an example of Alice setting a Policy on the NuCypher network.
# In this example, Alice uses n=1, which is almost always a bad idea.  Don't do it.

# WIP w/ [email protected]

import datetime
import sys

from examples.sandbox_resources import SandboxNetworkyStuff
from nucypher.characters import Alice, Bob, Ursula
from nucypher.data_sources import DataSource
from nucypher.network.node import NetworkyStuff
import maya

# This is already running in another process.
URSULA = Ursula.from_rest_url(NetworkyStuff(), address="localhost", port=3601)
network_middleware = SandboxNetworkyStuff([URSULA])

#########
# Alice #
#########

ALICE = Alice(network_middleware=network_middleware)

# Here are our Policy details.
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
m = 1
n = 1
label = b"secret/files/and/stuff"

# Alice gets on the network and, knowing about at least one Ursula,