|
@@ -156,6 +156,7 @@ class VanillaExtendedCircuitCell(RelayCell):
|
|
|
def __init__(self, ntor_reply):
|
|
|
self.ntor_reply = ntor_reply
|
|
|
|
|
|
+
|
|
|
# It is intentional that TelescopingCreateCircuitMsg is a RelayNetMsg and
|
|
|
# not a RelayCell. This is the message that _creates_ the circuit, so
|
|
|
# it can't be sent as a cell _within_ the circuit.
|
|
@@ -167,6 +168,7 @@ class TelescopingCreateCircuitMsg(RelayNetMsg):
|
|
|
self.circid = circid
|
|
|
self.ntor_request = ntor_request
|
|
|
|
|
|
+
|
|
|
class TelescopingCreatedCircuitCell(RelayCell):
|
|
|
"""The message for responding to circuit creation in Telescoping Walking
|
|
|
Onions."""
|
|
@@ -174,6 +176,7 @@ class TelescopingCreatedCircuitCell(RelayCell):
|
|
|
def __init__(self, ntor_reply):
|
|
|
self.ntor_reply = ntor_reply
|
|
|
|
|
|
+
|
|
|
class TelescopingExtendCircuitCell(RelayCell):
|
|
|
"""The message for requesting circuit extension in Telescoping Walking
|
|
|
Onions."""
|
|
@@ -182,6 +185,7 @@ class TelescopingExtendCircuitCell(RelayCell):
|
|
|
self.idx = idx
|
|
|
self.ntor_request = ntor_request
|
|
|
|
|
|
+
|
|
|
class TelescopingExtendedCircuitCell(RelayCell):
|
|
|
"""The message for responding to circuit extension in Telescoping Walking
|
|
|
Onions."""
|
|
@@ -190,28 +194,28 @@ class TelescopingExtendedCircuitCell(RelayCell):
|
|
|
self.ntor_reply = ntor_reply
|
|
|
self.snip = snip
|
|
|
|
|
|
+
|
|
|
class SinglePassCreateCircuitMsg(RelayNetMsg):
|
|
|
"""The message for requesting circuit creation in Single Pass Onion
|
|
|
Routing. This is used to extend a Single-Pass circuit by clients."""
|
|
|
|
|
|
- def __init__(self, circid, ntor_request, client_path_selection_key, ttl):
|
|
|
+ def __init__(self, circid, ntor_request, client_path_selection_key,
|
|
|
+ ttl=2):
|
|
|
self.circid = circid
|
|
|
self.ntor_request = ntor_request
|
|
|
- self.client_path_selection_key = client_path_selection_key
|
|
|
+ self.clipathselkey = bytes(client_path_selection_key)
|
|
|
self.ttl = ttl
|
|
|
|
|
|
+
|
|
|
class SinglePassCreatedCircuitCell(RelayCell):
|
|
|
"""The message for responding to circuit creation in Single-Pass Walking
|
|
|
Onions."""
|
|
|
|
|
|
- def __init__(self, ntor_reply, snip, vrf_output, ttl, encrypted_cell):
|
|
|
+ def __init__(self, ntor_reply, encrypted_cell):
|
|
|
self.ntor_reply = ntor_reply
|
|
|
- self.snip = snip
|
|
|
- self.vrf_output = vrf_output
|
|
|
- self.ttl = ttl
|
|
|
- # the above fields are sent in plaintext, the below is encrypted
|
|
|
- # information
|
|
|
- self.encrypted_cell = encrypted_cell
|
|
|
+ # The above field is sent in plaintext; the below is an
|
|
|
+ # SinglePassCreatedEnc, or None if this is the last layer
|
|
|
+ self.enc = encrypted_cell
|
|
|
|
|
|
|
|
|
class EncryptedCell(RelayCell):
|
|
@@ -235,6 +239,14 @@ class EncryptedCell(RelayCell):
|
|
|
return self.plaintext.size()
|
|
|
|
|
|
|
|
|
+class SinglePassCreatedEnc(EncryptedCell):
|
|
|
+ """The nested encrypted informaion inside a
|
|
|
+ SinglePassCreatedCircuitCell. nextlayer is itself a
|
|
|
+ SinglePassCreatedCircuitCell."""
|
|
|
+ def __init__(self, key, snip, vrf_output, nextlayer):
|
|
|
+ super().__init__(key, (snip, vrf_output, nextlayer))
|
|
|
+
|
|
|
+
|
|
|
class RelayFallbackTerminationError(Exception):
|
|
|
"""An exception raised when someone tries to terminate a fallback
|
|
|
relay."""
|
|
@@ -545,24 +557,24 @@ class SinglePassCreatedRelayHandler:
|
|
|
"""Handle a SinglePassCreatedCircuitCell received by a _relay_ that
|
|
|
recently received a SinglePassCreateCircuitMsg from this relay."""
|
|
|
|
|
|
- def __init__(self, ntorreply, next_snip, vrf_output, ttl):
|
|
|
+ def __init__(self, ntorreply, next_snip, vrf_output, enckey):
|
|
|
self.ntorreply = ntorreply
|
|
|
self.next_snip = next_snip
|
|
|
self.vrf_output = vrf_output
|
|
|
- self.ttl = ttl
|
|
|
+ self.enckey = enckey
|
|
|
|
|
|
def received_cell(self, circhandler, cell):
|
|
|
- logging.debug("Handle a SinglePassCreatedCircuitCell received by a relay, my ttl is %s", str(self.ttl))
|
|
|
+ logging.debug("Handle a SinglePassCreatedCircuitCell received by a relay")
|
|
|
# Remove ourselves from handling a second
|
|
|
# SinglePassCreatedCircuitCell on this circuit
|
|
|
circhandler.replace_celltype_handler(SinglePassCreatedCircuitCell, None)
|
|
|
- logging.debug("Sending a SinglePassCreatedCell after receiving one from %s; my ttl is %s", self.next_snip.snipdict['addr'], str(self.ttl))
|
|
|
+ logging.debug("Sending a SinglePassCreatedCell after receiving one from %s", self.next_snip.snipdict['addr'])
|
|
|
|
|
|
- # Just forward a SinglePassCreatedCircuitCell back towards the
|
|
|
- # client
|
|
|
+ # Forward a SinglePassCreatedCircuitCell back towards the client
|
|
|
circhandler.adjacent_circuit_handler.channel_send_cell(
|
|
|
- SinglePassCreatedCircuitCell(cell.ntor_reply, self.next_snip,
|
|
|
- self.vrf_output, self.ttl, cell))
|
|
|
+ SinglePassCreatedCircuitCell(cell.ntor_reply,
|
|
|
+ SinglePassCreatedEnc(self.enckey, self.next_snip,
|
|
|
+ self.vrf_output, cell)))
|
|
|
|
|
|
|
|
|
class CircuitHandler:
|
|
@@ -957,7 +969,7 @@ class RelayChannelManager(ChannelManager):
|
|
|
# Send the ntor reply, but no need to send the snip for the next
|
|
|
# relay or vrf proof, as this is the last relay in the circuit.
|
|
|
self.send_msg(CircuitCellMsg(msg.circid,
|
|
|
- SinglePassCreatedCircuitCell(reply, None, None, 0, None)), peeraddr)
|
|
|
+ SinglePassCreatedCircuitCell(reply, None)), peeraddr)
|
|
|
|
|
|
elif isinstance(msg, SinglePassCreateCircuitMsg) and msg.ttl > 0:
|
|
|
logging.debug("RelayChannelManager: Single-Pass TTL is greater than 0; extending")
|
|
@@ -974,13 +986,13 @@ class RelayChannelManager(ChannelManager):
|
|
|
# circuit extension key
|
|
|
enckey = nacl.hash.sha256(secret + b'downstream')
|
|
|
deckey = nacl.hash.sha256(secret + b'upstream')
|
|
|
- circhandler.add_crypt_layer(enckey, deckey)
|
|
|
|
|
|
# here, we will directly extend the circuit ourselves, after
|
|
|
# determining the next relay using the client's path selection
|
|
|
# key in conjunction with our own
|
|
|
- idx_as_hex, blinded_client_path_selection_key = Sphinx.server(msg.client_path_selection_key,
|
|
|
- self.path_selection_key, b'circuit', False, self.perfstats)
|
|
|
+ idx_as_hex, blinded_client_path_selection_key = \
|
|
|
+ Sphinx.server(nacl.public.PublicKey(msg.clipathselkey),
|
|
|
+ self.path_selection_key, b'circuit', False, self.perfstats)
|
|
|
|
|
|
logging.debug("RelayChannelManager: Unimplemented! need to translate idx into endive index")
|
|
|
logging.debug("RelayChannelManager: Unimplemented! need to pick the next relay using the shared secret between the client and the relay.")
|
|
@@ -1011,12 +1023,15 @@ class RelayChannelManager(ChannelManager):
|
|
|
newcirchandler.replace_celltype_handler(
|
|
|
SinglePassCreatedCircuitCell,
|
|
|
SinglePassCreatedRelayHandler(ntorreply, next_hop,
|
|
|
- vrf_output, msg.ttl))
|
|
|
+ vrf_output, enckey))
|
|
|
|
|
|
# Send the next create message to the next hop
|
|
|
nexthopchannel.send_msg(SinglePassCreateCircuitMsg(newcircid,
|
|
|
blinded_client_encr_key, blinded_client_path_selection_key,
|
|
|
msg.ttl-1))
|
|
|
+
|
|
|
+ # Now set up the crypto
|
|
|
+ circhandler.add_crypt_layer(enckey, deckey)
|
|
|
else:
|
|
|
return super().received_msg(msg, peeraddr, channel)
|
|
|
|
|
@@ -1052,8 +1067,10 @@ class Relay(network.Server):
|
|
|
network.thenetwork.wantepochticks(self, True, end=True)
|
|
|
network.thenetwork.wantepochticks(self, True)
|
|
|
|
|
|
+ # Create the path selection key for Single-Pass Walking Onions
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
self.path_selection_key = nacl.public.PrivateKey.generate()
|
|
|
+ self.perfstats.keygens += 1
|
|
|
else:
|
|
|
self.path_selection_key = None
|
|
|
|
|
@@ -1098,6 +1115,10 @@ class Relay(network.Server):
|
|
|
self.channelmgr.get_consensus()
|
|
|
|
|
|
def newepoch(self, epoch):
|
|
|
+ # Rotate the path selection key for Single-Pass Walking Onions
|
|
|
+ if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
+ self.path_selection_key = nacl.public.PrivateKey.generate()
|
|
|
+ self.perfstats.keygens += 1
|
|
|
self.uploaddesc()
|
|
|
|
|
|
def uploaddesc(self, upload=True):
|
|
@@ -1112,7 +1133,7 @@ class Relay(network.Server):
|
|
|
descdict["flags"] = self.flags
|
|
|
|
|
|
if network.thenetwork.womode == network.WOMode.SINGLEPASS:
|
|
|
- descdict["path_selection_key"] = self.path_selection_key
|
|
|
+ descdict["pathselkey"] = bytes(self.path_selection_key)
|
|
|
|
|
|
desc = dirauth.RelayDescriptor(descdict)
|
|
|
desc.sign(self.idkey, self.perfstats)
|