Browse Source

Single Pass now constructing working circuits with random choice of next hop

Ian Goldberg 4 years ago
parent
commit
38f5bdf0bf
2 changed files with 49 additions and 12 deletions
  1. 38 4
      client.py
  2. 11 8
      relay.py

+ 38 - 4
client.py

@@ -71,8 +71,8 @@ class TelescopingCreatedHandler:
     def __init__(self, channelmgr, ntor):
         self.channelmgr = channelmgr
         self.ntor = ntor
-        self.onionkey = self.channelmgr.guard.snipdict['onionkey']
-        self.idkey = self.channelmgr.guard.snipdict['idkey']
+        self.onionkey = self.channelmgr.guard.snipdict["onionkey"]
+        self.idkey = self.channelmgr.guard.snipdict["idkey"]
 
     def received_cell(self, circhandler, cell):
         logging.debug("Received cell in TelescopingCreatedHandler")
@@ -176,8 +176,42 @@ class SinglePassCreatedHandler:
         self.client_key = client_key
 
     def received_cell(self, circhandler, cell):
-        logging.debug("Received cell in SinglePassCreatedHandler")
-        sys.exit("not yet implemented")
+        # We should only get one relay.SinglePassCreatedCircuitCell per
+        # circuit
+        circhandler.replace_celltype_handler(relay.SinglePassCreatedCircuitCell, None)
+
+        # The circuit always starts with the guard
+        circhandler.circuit_descs.append(self.channelmgr.guard)
+
+        # Process each layer of the message
+        while cell is not None:
+            lasthop = circhandler.circuit_descs[-1]
+            onionkey = lasthop.snipdict["onionkey"]
+            idkey = lasthop.snipdict["idkey"]
+            pathselkey = lasthop.snipdict["pathselkey"]
+            if cell.enc is None:
+                secret = self.ntor.verify(cell.ntor_reply, onionkey, idkey)
+                enckey = nacl.hash.sha256(secret + b'upstream')
+                deckey = nacl.hash.sha256(secret + b'downstream')
+                circhandler.add_crypt_layer(enckey, deckey)
+                cell = None
+            else:
+                secret = self.ntor.verify(cell.ntor_reply, onionkey, \
+                        idkey, b'circuit')
+                enckey = nacl.hash.sha256(secret + b'upstream')
+                deckey = nacl.hash.sha256(secret + b'downstream')
+                createdkey = nacl.hash.sha256(secret + b'created')
+                circhandler.add_crypt_layer(enckey, deckey)
+                (snip, vrfout, nextlayer) = cell.enc.decrypt(createdkey)
+                # Check the signature on the SNIP
+                dirauth.SNIP.verify(snip, self.channelmgr.consensus,
+                        network.thenetwork.dirauthkeys()[0],
+                        self.channelmgr.perfstats)
+                # TODO: compute the index, check the VRF, ensure the
+                # SNIP is the correct one
+
+                circhandler.circuit_descs.append(snip)
+                cell = nextlayer
 
 
 class ClientChannelManager(relay.ChannelManager):

+ 11 - 8
relay.py

@@ -557,11 +557,11 @@ 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, enckey):
+    def __init__(self, ntorreply, next_snip, vrf_output, createdkey):
         self.ntorreply = ntorreply
         self.next_snip = next_snip
         self.vrf_output = vrf_output
-        self.enckey = enckey
+        self.createdkey = createdkey
 
     def received_cell(self, circhandler, cell):
         logging.debug("Handle a SinglePassCreatedCircuitCell received by a relay")
@@ -572,8 +572,8 @@ class SinglePassCreatedRelayHandler:
 
         # Forward a SinglePassCreatedCircuitCell back towards the client
         circhandler.adjacent_circuit_handler.channel_send_cell(
-            SinglePassCreatedCircuitCell(cell.ntor_reply,
-                SinglePassCreatedEnc(self.enckey, self.next_snip,
+            SinglePassCreatedCircuitCell(self.ntorreply,
+                SinglePassCreatedEnc(self.createdkey, self.next_snip,
                 self.vrf_output, cell)))
 
 
@@ -979,13 +979,15 @@ class RelayChannelManager(ChannelManager):
 
             # Create the ntor reply for the circuit-extension key, and derive
             # the client's next blinded key
-            (ntorreply, secret), blinded_client_encr_key = NTor.reply(self.onionkey, self.idpubkey,
+            (ntorreply, secret), blinded_client_encr_key = \
+                    NTor.reply(self.onionkey, self.idpubkey,
                     msg.ntor_request, self.perfstats,  b'circuit')
 
             # Set up the circuit to use the shared secret established from the
             # circuit extension key
             enckey = nacl.hash.sha256(secret + b'downstream')
             deckey = nacl.hash.sha256(secret + b'upstream')
+            createdkey = nacl.hash.sha256(secret + b'created')
 
             # here, we will directly extend the circuit ourselves, after
             # determining the next relay using the client's path selection
@@ -997,7 +999,7 @@ class RelayChannelManager(ChannelManager):
             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.")
 
-            # simpulate the VRF output for now
+            # simulate the VRF output for now
             vrf_output = VRF(self.path_selection_key,
                     self.relaypicker).get_output(idx_as_hex)
 
@@ -1005,9 +1007,10 @@ class RelayChannelManager(ChannelManager):
             if next_hop == None:
                 logging.debug("Client requested extending the circuit to a relay index that results in None, aborting. my circid: %s", str(circhandler.circid))
                 circhandler.close()
-            elif next_hop.snipdict["idkey"] == bytes(self.idpubkey) or next_hop.snipdict["addr"] == peeraddr:
+            elif next_hop.snipdict["idkey"] == bytes(self.idpubkey):
                 logging.debug("Client requested extending the circuit to a relay already in the path; aborting. my circid: %s", str(circhandler.circid))
                 circhandler.close()
+                return
 
             # Allocate a new circuit id to the requested next hop
             channelmgr = circhandler.channel.channelmgr
@@ -1023,7 +1026,7 @@ class RelayChannelManager(ChannelManager):
             newcirchandler.replace_celltype_handler(
                     SinglePassCreatedCircuitCell,
                     SinglePassCreatedRelayHandler(ntorreply, next_hop,
-                        vrf_output, enckey))
+                        vrf_output, createdkey))
 
             # Send the next create message to the next hop
             nexthopchannel.send_msg(SinglePassCreateCircuitMsg(newcircid,