async def receive_handshake_response( self, packet: HandshakeResponse, ) -> Tuple[SessionKeys, keys.PublicKey]: if not isinstance(packet, HandshakeResponse): raise Exception(f"Unhandled packet type: {type(packet)}") if not secrets.compare_digest(packet.token, self._initiating_packet.auth_tag): raise ValidationError("Mismatch between token") self.logger.debug('%s: receiving handshake response', self) # compute session keys ephemeral_private_key = keys.PrivateKey(secrets.token_bytes(32)) self.remote_public_key = packet.public_key expected_remote_node_id = public_key_to_node_id(self.remote_public_key) if expected_remote_node_id != self.remote_node_id: raise ValidationError( f"Remote node ids does not match expected node id: " f"{self.remote_node_id} != {self.remote_node_id}") session_keys = compute_session_keys( local_private_key=ephemeral_private_key, remote_public_key=packet.public_key, local_node_id=self.local_node_id, remote_node_id=self.remote_node_id, id_nonce=packet.id_nonce, is_initiator=True, ) return session_keys, ephemeral_private_key.public_key
class NodeFactory(factory.Factory): # type: ignore class Meta: model = Node node_id = factory.LazyFunction( lambda: public_key_to_node_id(PublicKeyFactory())) endpoint = factory.SubFactory(EndpointFactory)
def __init__(self, private_key: keys.PrivateKey, listen_on: Endpoint, ) -> None: self._private_key = private_key self.public_key = private_key.public_key self.local_node_id = public_key_to_node_id(self.public_key) self.listen_on = listen_on self.local_node = Node(self.local_node_id, self.listen_on) # Datagrams ( self._outbound_datagram_send_channel, self._outbound_datagram_receive_channel, ) = trio.open_memory_channel[Datagram](0) ( self._inbound_datagram_send_channel, self._inbound_datagram_receive_channel, ) = trio.open_memory_channel[Datagram](0) # Packets ( self._outbound_packet_send_channel, self._outbound_packet_receive_channel, ) = trio.open_memory_channel[NetworkPacket](0) ( self._inbound_packet_send_channel, self._inbound_packet_receive_channel, ) = trio.open_memory_channel[NetworkPacket](0) # Messages ( self._outbound_message_send_channel, self._outbound_message_receive_channel, ) = trio.open_memory_channel[MessageAPI[sedes.Serializable]](0) ( self._inbound_message_send_channel, self._inbound_message_receive_channel, ) = trio.open_memory_channel[MessageAPI[sedes.Serializable]](0) self.events = Events() self.pool = Pool( private_key=self._private_key, events=self.events, outbound_packet_send_channel=self._outbound_packet_send_channel, inbound_message_send_channel=self._inbound_message_send_channel, ) self.message_dispatcher = MessageDispatcher( self._outbound_message_send_channel, self._inbound_message_receive_channel, ) self._ready = trio.Event()
def __init__( self, private_key: keys.PrivateKey, events: EventsAPI, outbound_packet_send_channel: trio.abc.SendChannel[NetworkPacket], inbound_message_send_channel: trio.abc.SendChannel[MessageAPI[ sedes.Serializable]], ) -> None: self._private_key = private_key self.public_key = private_key.public_key self.local_node_id = public_key_to_node_id(self.public_key) self._sessions = {} self._events = events self._outbound_packet_send_channel = outbound_packet_send_channel self._inbound_message_send_channel = inbound_message_send_channel
async def receive_handshake_completion( self, packet: CompleteHandshakePacket) -> SessionKeys: self.logger.debug('%s: received handshake completion', self) remote_node_id = recover_source_id_from_tag( packet.tag, self.local_node_id, ) if remote_node_id != self.remote_node_id: raise ValidationError( f"Remote node ids do not match: {remote_node_id} != {self.remote_node_id}" ) self.remote_public_key = packet.header.public_key expected_remote_node_id = public_key_to_node_id(self.remote_public_key) if expected_remote_node_id != remote_node_id: raise ValidationError( f"Remote node ids does not match expected node id: " f"{remote_node_id} != {self.remote_node_id}") ephemeral_public_key = packet.header.ephemeral_public_key session_keys = compute_session_keys( local_private_key=self.private_key, remote_public_key=ephemeral_public_key, local_node_id=self.local_node_id, remote_node_id=self.remote_node_id, id_nonce=self.handshake_response_packet.id_nonce, is_initiator=False, ) self.decrypt_and_validate_auth_response( packet, session_keys.auth_response_key, self.handshake_response_packet.id_nonce, ) payload = self.decrypt_and_validate_message( packet, session_keys.decryption_key, ) message = Message( payload=payload, node=self.remote_node, ) await self._inbound_message_send_channel.send(message) return session_keys
def local_node_id(self) -> NodeID: return public_key_to_node_id(self.private_key.public_key)