Example #1
0
async def test_dispatcher_subscribe_request_response(tester, alice, bob):
    carol = tester.node()
    driver_a = tester.session_pair(alice, bob)
    driver_b = tester.session_pair(carol, alice)

    await driver_a.handshake()
    await driver_b.handshake()

    async with tester.dispatcher_pair(alice, bob) as (alice_dispatcher, _):
        async with tester.dispatcher_pair(alice, carol):
            request = OutboundMessage(
                PingMessage(b"\x12", alice.enr.sequence_number),
                bob.endpoint,
                bob.node_id,
            )
            async with alice_dispatcher.subscribe_request(
                    request, PongMessage) as subscription:
                await driver_a.initiator.send_ping(b"\x12")
                await driver_b.initiator.send_ping(b"\x34")
                await driver_b.recipient.send_pong(b"\x34")
                await driver_a.recipient.send_pong(b"\x12")

                with trio.fail_after(1):
                    response = await subscription.receive()

    assert response.sender_node_id == bob.node_id
    assert response.message.request_id == b"\x12"
Example #2
0
def test_handshake_packet_encoding(enr):
    initiator_key = b"\x01" * 16
    nonce = b"\x02" * 12
    source_node_id = b"\x03" * 32
    dest_node_id = b"\x04" * 32
    message = PingMessage(1, 0)
    auth_data = HandshakePacket(
        auth_data_head=HandshakeHeader(
            version=1,
            signature_size=64,
            ephemeral_key_size=33,
        ),
        id_signature=b"\x05" * 64,
        ephemeral_public_key=b"\x06" * 33,
        record=enr,
    )

    packet = Packet.prepare(
        nonce=nonce,
        initiator_key=initiator_key,
        message=message,
        auth_data=auth_data,
        source_node_id=source_node_id,
        dest_node_id=dest_node_id,
    )
    packet_wire_bytes = packet.to_wire_bytes()
    result = decode_packet(packet_wire_bytes, dest_node_id)

    assert result == packet
Example #3
0
async def test_dispatcher_send_message_with_existing_session(
        driver, alice, bob, paired_dispatchers):
    alice_dispatcher, _ = paired_dispatchers

    async with bob.events.ping_received.subscribe_and_wait():
        await alice_dispatcher.send_message(
            OutboundMessage(
                PingMessage(b"\x12", alice.enr.sequence_number),
                bob.endpoint,
                bob.node_id,
            ))

    async with bob.events.ping_received.subscribe_and_wait():
        await alice_dispatcher.send_message(
            OutboundMessage(
                PingMessage(b"\x34", alice.enr.sequence_number),
                bob.endpoint,
                bob.node_id,
            ))
Example #4
0
 async def ping(self, endpoint: Endpoint,
                node_id: NodeID) -> InboundMessage[PongMessage]:
     with self._get_request_id(node_id) as request_id:
         request = AnyOutboundMessage(
             PingMessage(request_id, self.enr_manager.enr.sequence_number),
             endpoint,
             node_id,
         )
         async with self.dispatcher.subscribe_request(
                 request, PongMessage) as subscription:
             with trio.fail_after(REQUEST_RESPONSE_TIMEOUT):
                 return await subscription.receive()
Example #5
0
    async def send_ping(
        self, endpoint: Endpoint, node_id: NodeID, *, request_id: Optional[int] = None,
    ) -> int:
        with self._get_request_id(node_id, request_id) as message_request_id:
            message = AnyOutboundMessage(
                PingMessage(message_request_id, self.enr_manager.enr.sequence_number),
                endpoint,
                node_id,
            )
            await self.dispatcher.send_message(message)

        return message_request_id
Example #6
0
async def test_dispatcher_send_message_creates_session(tester, driver, alice,
                                                       paired_dispatchers):
    carol = tester.node()
    alice_dispatcher, _ = paired_dispatchers

    async with alice.events.session_created.subscribe_and_wait():
        await alice_dispatcher.send_message(
            OutboundMessage(
                PingMessage(b"\x12", alice.enr.sequence_number),
                carol.endpoint,
                carol.node_id,
            ))
Example #7
0
async def test_dispatcher_bidirectional_communication(driver, alice, bob,
                                                      paired_dispatchers):
    alice_dispatcher, bob_dispatcher = paired_dispatchers
    async with alice.events.session_handshake_complete.subscribe_and_wait():
        async with bob.events.session_handshake_complete.subscribe_and_wait():
            async with alice.events.ping_sent.subscribe_and_wait():
                async with bob.events.ping_received.subscribe_and_wait():
                    await alice_dispatcher.send_message(
                        OutboundMessage(
                            PingMessage(b"\x12", alice.enr.sequence_number),
                            bob.endpoint,
                            bob.node_id,
                        ))
Example #8
0
 async def ping(
     self,
     node_id: NodeID,
     endpoint: Endpoint,
     *,
     request_id: Optional[bytes] = None,
 ) -> InboundMessage[PongMessage]:
     with self.request_tracker.reserve_request_id(node_id,
                                                  request_id) as request_id:
         request = AnyOutboundMessage(
             PingMessage(request_id, self.enr_manager.enr.sequence_number),
             endpoint,
             node_id,
         )
         async with self.dispatcher.subscribe_request(
                 request, PongMessage) as subscription:
             return await subscription.receive()
Example #9
0
def test_who_are_you_packet_encoding():
    initiator_key = b"\x01" * 16
    aes_gcm_nonce = b"\x02" * 12
    dest_node_id = b"\x04" * 32
    message = PingMessage(b"\x01", 0)
    auth_data = WhoAreYouPacket(id_nonce=b"\x06" * 16,
                                enr_sequence_number=0x07)

    packet = Packet.prepare(
        aes_gcm_nonce=aes_gcm_nonce,
        initiator_key=initiator_key,
        message=message,
        auth_data=auth_data,
        dest_node_id=dest_node_id,
    )
    packet_wire_bytes = packet.to_wire_bytes()
    result = decode_packet(packet_wire_bytes, dest_node_id)

    assert result == packet
Example #10
0
def test_message_packet_encoding():
    initiator_key = b"\x01" * 16
    aes_gcm_nonce = b"\x02" * 12
    source_node_id = b"\x03" * 32
    dest_node_id = b"\x04" * 32
    message = PingMessage(b"\x01", 0)
    auth_data = MessagePacket(source_node_id)

    packet = Packet.prepare(
        aes_gcm_nonce=aes_gcm_nonce,
        initiator_key=initiator_key,
        message=message,
        auth_data=auth_data,
        dest_node_id=dest_node_id,
    )
    packet_wire_bytes = packet.to_wire_bytes()
    result = decode_packet(packet_wire_bytes, dest_node_id)

    assert result == packet
Example #11
0
def do_message_packet_fixture_decoding_test(fixture):
    dest_node_id = decode_hex(fixture["dest-node-id"])
    expected_auth_data = MessagePacket(source_node_id=decode_hex(
        fixture["src-node-id"]), )
    expected_message = PingMessage(
        request_id=decode_hex(fixture["packet"]["message"]["req-id"]),
        enr_seq=to_int(hexstr=fixture["packet"]["message"]["enr-seq"]),
    )
    encoded_packet = decode_hex(fixture["encoded"])
    packet = decode_packet(encoded_packet, dest_node_id)
    assert packet.auth_data == expected_auth_data

    aes_gcm_nonce = decode_hex(fixture["nonce"])

    actual_message = decode_message(
        decryption_key=decode_hex(fixture["read-key"]),
        aes_gcm_nonce=aes_gcm_nonce,
        message_cipher_text=packet.message_cipher_text,
        authenticated_data=packet.challenge_data,
    )
    assert actual_message == expected_message
Example #12
0
    async def send_ping(
        self,
        node_id: NodeID,
        endpoint: Endpoint,
        *,
        enr_seq: Optional[int] = None,
        request_id: Optional[bytes] = None,
    ) -> bytes:
        if enr_seq is None:
            enr_seq = self.enr_manager.enr.sequence_number

        with self.request_tracker.reserve_request_id(
                node_id, request_id) as message_request_id:
            message = AnyOutboundMessage(
                PingMessage(message_request_id, enr_seq),
                endpoint,
                node_id,
            )
            await self.dispatcher.send_message(message)

        return message_request_id
Example #13
0
def test_who_are_you_packet_encoding():
    initiator_key = b"\x01" * 16
    nonce = b"\x02" * 12
    source_node_id = b"\x03" * 32
    dest_node_id = b"\x04" * 32
    message = PingMessage(1, 0)
    auth_data = WhoAreYouPacket(request_nonce=b"\x05" * 12,
                                id_nonce=b"\x06" * 32,
                                enr_sequence_number=0x07)

    packet = Packet.prepare(
        nonce=nonce,
        initiator_key=initiator_key,
        message=message,
        auth_data=auth_data,
        source_node_id=source_node_id,
        dest_node_id=dest_node_id,
    )
    packet_wire_bytes = packet.to_wire_bytes()
    result = decode_packet(packet_wire_bytes, dest_node_id)

    assert result == packet
Example #14
0
async def test_session_unexpected_packets(driver):
    recipient = driver.recipient.node
    initiator = driver.initiator.node

    assert driver.initiator.session.is_before_handshake
    assert driver.recipient.session.is_before_handshake

    # initiate the handshake
    await driver.initiator.send_ping(b"\x12")

    assert driver.initiator.session.is_during_handshake
    assert driver.recipient.session.is_before_handshake

    with trio.fail_after(2):
        # The recipient should discard any non `MessagePacket` at this stage
        # since it is impossible for the initiator to have valid `SessionKeys`
        # since the recipient has not yet sent the `WhoAreYouPacket`
        async with driver.recipient.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.who_are_you(dest_node_id=recipient.node_id,)
            )
        async with driver.recipient.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.handshake(
                    source_node_id=initiator.node_id, dest_node_id=recipient.node_id,
                )
            )

        # The initiator should discard any non `WhoAreYouPacket` packet at this stage since it is
        # impossible for the recipient to have valid `SessionKeys` since the
        # initiator has not yet sent the `HandshakePacket`
        async with driver.initiator.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.message(
                    source_node_id=recipient.node_id, dest_node_id=initiator.node_id,
                )
            )
        async with driver.initiator.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.handshake(
                    source_node_id=recipient.node_id, dest_node_id=initiator.node_id,
                )
            )

    # Transmit the initation packet
    await driver.transmit_one(driver.initiator)

    assert driver.initiator.session.is_during_handshake
    assert driver.recipient.session.is_during_handshake

    with trio.fail_after(2):
        # The recipient should discard a WhoAreYouPacket since there is no
        # reason for the initiator to send such a packet.
        async with driver.recipient.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.who_are_you(dest_node_id=recipient.node_id,)
            )

        # The initiator should discard a HandshakePacket since there is no
        # reason for the recipient to send such a packet
        async with driver.initiator.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.handshake(
                    source_node_id=recipient.node_id, dest_node_id=initiator.node_id,
                )
            )

    # Transmit the who-are-you packet
    await driver.transmit_one(driver.recipient)

    assert driver.initiator.session.is_after_handshake
    assert driver.recipient.session.is_during_handshake

    with trio.fail_after(2):
        # The recipient should discard a WhoAreYouPacket since there is no
        # reason for the initiator to send such a packet.
        async with driver.recipient.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.who_are_you(dest_node_id=recipient.node_id,)
            )

        # The recipient should buffer any message packets it receives at this
        # stage since they could be valid packets recieved out of order since
        # the initiator can now have valid session keys.
        await driver.send_packet(
            PacketFactory.message(
                aes_gcm_nonce=driver.initiator.session.get_encryption_nonce(),
                initiator_key=driver.initiator.session.keys.encryption_key,
                message=PingMessage(b"\x34", initiator.enr.sequence_number),
                source_node_id=initiator.node_id,
                dest_node_id=recipient.node_id,
            )
        )

        # The initiator should discard a HandshakePacket since there is no
        # reason for the recipient to send such a packet
        async with driver.initiator.events.packet_discarded.subscribe_and_wait():
            await driver.send_packet(
                PacketFactory.handshake(
                    source_node_id=recipient.node_id, dest_node_id=initiator.node_id,
                )
            )

    # Transmit the handshake packet
    await driver.transmit_one(driver.initiator)

    # handshake should be complete now
    assert driver.initiator.session.is_after_handshake
    assert driver.recipient.session.is_after_handshake

    async with driver.transmit():
        initiation_ping = await driver.recipient.next_message()
        out_of_order_ping = await driver.recipient.next_message()

    assert initiation_ping.message.request_id == b"\x12"
    assert out_of_order_ping.message.request_id == b"\x34"
Example #15
0
def do_handshake_packet_fixture_decoding_test(fixture):
    source_node_id = decode_hex(fixture["src-node-id"])
    dest_node_id = decode_hex(fixture["dest-node-id"])
    encoded_packet = decode_hex(fixture["encoded"])
    ping_enr_seq = to_int(hexstr=fixture["packet"]["message"]["enr-seq"])
    who_are_you_enr_seq = to_int(
        hexstr=fixture["handshake-inputs"]["whoareyou"]["enr-seq"])

    if who_are_you_enr_seq == ping_enr_seq and who_are_you_enr_seq != 0:
        should_have_record = False
    else:
        should_have_record = True

    # ephemeral_private_key = decode_hex(fixture['handshake-inputs']['ephemeral-key'])
    ephemeral_public_key = decode_hex(
        fixture["handshake-inputs"]["ephemeral-pubkey"])
    # ephemeral_private_key = decode_hex(fixture["handshake-inputs"]["ephemeral-key"])

    # request_nonce = decode_hex(fixture['handshake-inputs']['whoareyou']['request-nonce'])
    challenge_data = decode_hex(
        fixture["handshake-inputs"]["whoareyou"]["challenge-data"])
    masking_iv, static_header, who_are_you = extract_challenge_data(
        challenge_data)

    id_nonce = decode_hex(fixture["handshake-inputs"]["whoareyou"]["id-nonce"])
    assert who_are_you.id_nonce == id_nonce

    aes_gcm_nonce = decode_hex(fixture["nonce"])
    # TODO: why doesn't this match
    # assert static_header.aes_gcm_nonce == aes_gcm_nonce

    signature_inputs = V4HandshakeScheme.signature_inputs_cls(
        iv=masking_iv,
        header=static_header,
        who_are_you=WhoAreYouPacket(id_nonce, who_are_you_enr_seq),
        ephemeral_public_key=ephemeral_public_key,
        recipient_node_id=dest_node_id,
    )

    id_nonce_signature = V4HandshakeScheme.create_id_nonce_signature(
        signature_inputs=signature_inputs,
        private_key=NODE_KEY_A,
    )

    packet = decode_packet(encoded_packet, dest_node_id)
    expected_auth_data = HandshakePacket(
        auth_data_head=HandshakeHeader(source_node_id, 64, 33),
        id_signature=id_nonce_signature,
        ephemeral_public_key=ephemeral_public_key,
        record=packet.auth_data.record,
    )

    assert expected_auth_data == packet.auth_data
    assert packet.header.aes_gcm_nonce == aes_gcm_nonce

    if should_have_record:
        assert packet.auth_data.record is not None
        assert packet.auth_data.record.node_id == source_node_id
    else:
        assert packet.auth_data.record is None

    expected_message = PingMessage(
        request_id=decode_hex(fixture["packet"]["message"]["req-id"]),
        enr_seq=to_int(hexstr=fixture["packet"]["message"]["enr-seq"]),
    )
    actual_message = decode_message(
        decryption_key=decode_hex(fixture["read-key"]),
        aes_gcm_nonce=aes_gcm_nonce,
        message_cipher_text=packet.message_cipher_text,
        authenticated_data=packet.challenge_data,
    )
    assert expected_message == actual_message
Example #16
0
 async def send_ping(self, request_id: Optional[int] = None) -> PingMessage:
     if request_id is None:
         request_id = secrets.randbits(32)
     message = PingMessage(request_id, self.node.enr.sequence_number)
     await self.send_message(message)
     return message