relay.py 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382
  1. #!/usr/bin/env python3
  2. import random # For simulation, not cryptography!
  3. import math
  4. import sys
  5. import logging
  6. import nacl.utils
  7. import nacl.signing
  8. import nacl.public
  9. import nacl.hash
  10. import nacl.bindings
  11. import hashlib
  12. from collections import namedtuple
  13. import network
  14. import dirauth
  15. VRFOutput = namedtuple('VRFOutput', 'output proof')
  16. class VRF():
  17. def __init__(self, private_key, relaypicker):
  18. self.private_key = private_key
  19. self.relaypicker = relaypicker
  20. def get_output(self, vrf_input):
  21. output = self.relaypicker.pick_weighted_relay_index()
  22. m = hashlib.sha256()
  23. m.update(str(output).encode())
  24. return VRFOutput(output, m.digest())
  25. class RelayNetMsg(network.NetMsg):
  26. """The subclass of NetMsg for messages between relays and either
  27. relays or clients."""
  28. class RelayGetConsensusMsg(RelayNetMsg):
  29. """The subclass of RelayNetMsg for fetching the consensus. Sent by
  30. clients to relays."""
  31. class RelayConsensusMsg(RelayNetMsg):
  32. """The subclass of RelayNetMsg for returning the consensus from
  33. relays to clients, in response to RelayGetConsensusMsg."""
  34. def __init__(self, consensus):
  35. self.consensus = consensus
  36. class RelayGetConsensusDiffMsg(RelayNetMsg):
  37. """The subclass of RelayNetMsg for fetching the consensus, if the
  38. requestor already has the previous consensus. Sent by clients to
  39. relays."""
  40. class RelayConsensusDiffMsg(RelayNetMsg):
  41. """The subclass of RelayNetMsg for returning the consensus, if the
  42. requestor already has the previous consensus. We don't _actually_
  43. produce the diff at this time; we just charge fewer bytes for this
  44. message. Sent by relays to clients in response to
  45. RelayGetConsensusDiffMsg."""
  46. def __init__(self, consensus):
  47. self.consensus = consensus
  48. def size(self):
  49. if network.symbolic_byte_counters:
  50. return super().size()
  51. return math.ceil(RelayConsensusMsg(self.consensus).size() \
  52. * network.P_Delta)
  53. class RelayRandomHopMsg(RelayNetMsg):
  54. """A message used for testing, that hops from relay to relay
  55. randomly until its TTL expires."""
  56. def __init__(self, ttl):
  57. self.ttl = ttl
  58. def __str__(self):
  59. return "RandomHop TTL=%d" % self.ttl
  60. class CircuitCellMsg(RelayNetMsg):
  61. """Send a message tagged with a circuit id. This is the container
  62. class for all RelayCell messages."""
  63. def __init__(self, circuitid, cell):
  64. self.circid = circuitid
  65. self.cell = cell
  66. def __str__(self):
  67. return "C%d:%s" % (self.circid, self.cell)
  68. def size(self):
  69. # circuitids are 4 bytes
  70. return 4 + self.cell.size()
  71. class RelayCell(RelayNetMsg):
  72. """All cells (which are sent inside a CircuitCellMsg, and so do not
  73. need their own circuitid) should be a subclass of this class."""
  74. class StringCell(RelayCell):
  75. """Send an arbitrary string as a cell."""
  76. def __init__(self, str):
  77. self.data = str
  78. def __str__(self):
  79. return self.data.__str__()
  80. class CloseCell(RelayCell):
  81. """Close the circuit this cell was sent on. It should be sent
  82. _unencrypted_ (not within an EncryptedCell), and relays that receive
  83. one should forward it along the adjacent circuit, then close both
  84. the circuit it was received on and the adjacent one."""
  85. # It is intentional that VanillaCreateCircuitMsg is a RelayNetMsg and
  86. # not a RelayCell. This is the message that _creates_ the circuit, so
  87. # it can't be sent as a cell _within_ the circuit.
  88. class VanillaCreateCircuitMsg(RelayNetMsg):
  89. """The message for requesting circuit creation in Vanilla Onion
  90. Routing."""
  91. def __init__(self, circid, ntor_request):
  92. self.circid = circid
  93. self.ntor_request = ntor_request
  94. class VanillaCreatedCircuitCell(RelayCell):
  95. """The message for responding to circuit creation in Vanilla Onion
  96. Routing."""
  97. def __init__(self, ntor_reply):
  98. self.ntor_reply = ntor_reply
  99. class VanillaExtendCircuitCell(RelayCell):
  100. """The message for requesting circuit extension in Vanilla Onion
  101. Routing."""
  102. def __init__(self, hopaddr, ntor_request):
  103. self.hopaddr = hopaddr
  104. self.ntor_request = ntor_request
  105. class VanillaExtendedCircuitCell(RelayCell):
  106. """The message for responding to circuit extension in Vanilla Onion
  107. Routing."""
  108. def __init__(self, ntor_reply):
  109. self.ntor_reply = ntor_reply
  110. # It is intentional that TelescopingCreateCircuitMsg is a RelayNetMsg and
  111. # not a RelayCell. This is the message that _creates_ the circuit, so
  112. # it can't be sent as a cell _within_ the circuit.
  113. class TelescopingCreateCircuitMsg(RelayNetMsg):
  114. """The message for requesting circuit creation in Telescoping Onion
  115. Routing."""
  116. def __init__(self, circid, ntor_request):
  117. self.circid = circid
  118. self.ntor_request = ntor_request
  119. class TelescopingCreatedCircuitCell(RelayCell):
  120. """The message for responding to circuit creation in Telescoping Walking
  121. Onions."""
  122. def __init__(self, ntor_reply):
  123. self.ntor_reply = ntor_reply
  124. class TelescopingExtendCircuitCell(RelayCell):
  125. """The message for requesting circuit extension in Telescoping Walking
  126. Onions."""
  127. def __init__(self, idx, ntor_request):
  128. self.idx = idx
  129. self.ntor_request = ntor_request
  130. class TelescopingExtendedCircuitCell(RelayCell):
  131. """The message for responding to circuit extension in Telescoping Walking
  132. Onions."""
  133. def __init__(self, ntor_reply, snip):
  134. self.ntor_reply = ntor_reply
  135. self.snip = snip
  136. class SinglePassCreateCircuitMsg(RelayNetMsg):
  137. """The message for requesting circuit creation in Single Pass Onion
  138. Routing. This is used to extend a Single-Pass circuit by clients."""
  139. def __init__(self, circid, ntor_request, client_path_selection_key, ttl):
  140. self.circid = circid
  141. self.ntor_request = ntor_request
  142. self.client_path_selection_key = client_path_selection_key
  143. self.ttl = ttl
  144. class SinglePassCreatedCircuitCell(RelayCell):
  145. """The message for responding to circuit creation in Single-Pass Walking
  146. Onions."""
  147. def __init__(self, ntor_reply, snip, vrf_output, ttl, encrypted_cell):
  148. self.ntor_reply = ntor_reply
  149. self.snip = snip
  150. self.vrf_output = vrf_output
  151. self.ttl = ttl
  152. # the above fields are sent in plaintext, the below is encrypted
  153. # information
  154. self.encrypted_cell = encrypted_cell
  155. class EncryptedCell(RelayCell):
  156. """Send a message encrypted with a symmetric key. In this
  157. implementation, the encryption is not really done. A hash of the
  158. key is stored with the message so that it can be checked at
  159. decryption time."""
  160. def __init__(self, key, msg):
  161. self.keyhash = nacl.hash.sha256(key)
  162. self.plaintext = msg
  163. def decrypt(self, key):
  164. keyhash = nacl.hash.sha256(key)
  165. if keyhash != self.keyhash:
  166. raise ValueError("EncryptedCell key mismatch")
  167. return self.plaintext
  168. def size(self):
  169. # Current Tor actually has no overhead for encryption
  170. return self.plaintext.size()
  171. class RelayFallbackTerminationError(Exception):
  172. """An exception raised when someone tries to terminate a fallback
  173. relay."""
  174. class Sphinx:
  175. """Implement the public-key reblinding technique based on Sphinx.
  176. This does a few more public-key operations than it would strictly
  177. need to if we were using a group implementation that (unlike nacl)
  178. supported the operations we needed directly. The biggest issue is
  179. that nacl insists the high bit is set on private keys, which means
  180. we can't just multiply private keys together to get a new private
  181. key, and do a single DH operation with that resulting key; we have
  182. to perform a linear number of DH operations instead, per node in the
  183. circuit, so a quadratic number of DH operations total."""
  184. @staticmethod
  185. def makeblindkey(shared_secret, domain_separator, perfstats):
  186. """Create a Sphinx reblinding key (a PrivateKey) out of a shared
  187. secret and a domain separator (both bytestrings). The domain
  188. separator is just a constant bytestring like b'data' or
  189. b'circuit' for the data-protecting and circuit-protecting
  190. public-key elements respectively."""
  191. rawkey = nacl.hash.sha256(domain_separator + shared_secret,
  192. encoder=nacl.encoding.RawEncoder)
  193. perfstats.keygens += 1
  194. # The PrivateKey constructor does the Curve25519 pinning of
  195. # certain bits of the key to 0 and 1
  196. return nacl.public.PrivateKey(rawkey)
  197. @staticmethod
  198. def reblindpubkey(blindkey, pubkey, perfstats):
  199. """Create a Sphinx reblinded PublicKey out of a reblinding key
  200. (output by makeblindkey) and a (possibly already reblinded)
  201. PublicKey."""
  202. new_pubkey = nacl.bindings.crypto_scalarmult(bytes(blindkey),
  203. bytes(pubkey))
  204. perfstats.dhs += 1
  205. return nacl.public.PublicKey(new_pubkey)
  206. @staticmethod
  207. def client(client_privkey, blindkey_list, server_pubkey,
  208. domain_separator, is_last, perfstats):
  209. """Given the client's PrivateKey, a (possibly empty) list of
  210. reblinding keys, and the server's PublicKey, produce the shared
  211. secret and the new blinding key (to add to the list). The
  212. domain separator is as above. If is_last is true, don't bother
  213. creating the new blinding key, since this is the last iteration,
  214. and we won't be using it."""
  215. reblinded_server_pubkey = server_pubkey
  216. for blindkey in blindkey_list:
  217. reblinded_server_pubkey = Sphinx.reblindpubkey(blindkey,
  218. reblinded_server_pubkey, perfstats)
  219. sharedsecret = nacl.public.Box(client_privkey,
  220. reblinded_server_pubkey).shared_key()
  221. perfstats.dhs += 1
  222. if is_last:
  223. blindkey = None
  224. else:
  225. blindkey = Sphinx.makeblindkey(sharedsecret,
  226. domain_separator, perfstats)
  227. return sharedsecret, blindkey
  228. @staticmethod
  229. def server(client_pubkey, server_privkey, domain_separator, is_last,
  230. perfstats):
  231. """Given the client's PublicKey and the server's PrivateKey,
  232. produce the shared secret and the new reblinded client
  233. PublicKey. The domain separator is as above. If is_last is
  234. True, don't bother generating the new PublicKey, since we're the
  235. last server in the chain, and won't be using it."""
  236. sharedsecret = nacl.public.Box(server_privkey,
  237. client_pubkey).shared_key()
  238. perfstats.dhs += 1
  239. if is_last:
  240. blinded_pubkey = None
  241. else:
  242. blindkey = Sphinx.makeblindkey(sharedsecret, domain_separator,
  243. perfstats)
  244. blinded_pubkey = Sphinx.reblindpubkey(blindkey, client_pubkey,
  245. perfstats)
  246. return sharedsecret, blinded_pubkey
  247. class NTor:
  248. """A class implementing the ntor one-way authenticated key agreement
  249. scheme. The details are not exactly the same as either the ntor
  250. paper or Tor's implementation, but it will agree on keys and have
  251. the same number of public key operations."""
  252. def __init__(self, perfstats):
  253. self.perfstats = perfstats
  254. # Only used for Single-Pass Walking Onions; it is the sequence
  255. # of blinding keys used by Sphinx
  256. self.blinding_keys = []
  257. def request(self):
  258. """Create the ntor request message: X = g^x."""
  259. self.client_ephem_key = nacl.public.PrivateKey.generate()
  260. self.perfstats.keygens += 1
  261. return bytes(self.client_ephem_key.public_key)
  262. @staticmethod
  263. def reply(onion_privkey, idpubkey, client_pubkey, perfstats,
  264. sphinx_domainsep=None):
  265. """The server calls this static method to produce the ntor reply
  266. message: (Y = g^y, B = g^b, A = H(M, "verify")) and the shared
  267. secret S = H(M, "secret") for M = (X^y,X^b,ID,B,X,Y). If
  268. sphinx_domainsep is not None, also compute and return the Sphinx
  269. reblinded client request to pass to the next server."""
  270. if type(idpubkey) is not bytes:
  271. idpubkey = bytes(idpubkey)
  272. if type(client_pubkey) is bytes:
  273. client_pubkey = nacl.public.PublicKey(client_pubkey)
  274. server_ephem_key = nacl.public.PrivateKey.generate()
  275. perfstats.keygens += 1
  276. xykey = nacl.public.Box(server_ephem_key, client_pubkey).shared_key()
  277. xbkey = nacl.public.Box(onion_privkey, client_pubkey).shared_key()
  278. perfstats.dhs += 2
  279. M = xykey + xbkey + \
  280. idpubkey + \
  281. onion_privkey.public_key.encode(encoder=nacl.encoding.RawEncoder) + \
  282. server_ephem_key.public_key.encode(encoder=nacl.encoding.RawEncoder)
  283. A = nacl.hash.sha256(M + b'verify', encoder=nacl.encoding.RawEncoder)
  284. S = nacl.hash.sha256(M + b'secret', encoder=nacl.encoding.RawEncoder)
  285. if sphinx_domainsep is not None:
  286. blindkey = Sphinx.makeblindkey(S, sphinx_domainsep, perfstats)
  287. blinded_client_pubkey = Sphinx.reblindpubkey(blindkey,
  288. client_pubkey, perfstats)
  289. return ((bytes(server_ephem_key.public_key),
  290. bytes(onion_privkey.public_key), A),
  291. S), blinded_client_pubkey
  292. else:
  293. return ((bytes(server_ephem_key.public_key),
  294. bytes(onion_privkey.public_key), A), S)
  295. def verify(self, reply, onion_pubkey, idpubkey, sphinx_domainsep=None):
  296. """The client calls this method to verify the ntor reply
  297. message, passing the onion and id public keys for the server
  298. it's expecting to be talking to. If sphinx_domainsep is not
  299. None, also compute the reblinding key so that the client can
  300. reuse this same NTor object for the next server. Returns the
  301. shared secret on success, or raises ValueError on failure."""
  302. server_ephem_pubkey, server_onion_pubkey, authtag = reply
  303. if type(idpubkey) is not bytes:
  304. idpubkey = bytes(idpubkey)
  305. if type(server_ephem_pubkey) is bytes:
  306. server_ephem_pubkey = nacl.public.PublicKey(server_ephem_pubkey)
  307. if type(server_onion_pubkey) is bytes:
  308. server_onion_pubkey = nacl.public.PublicKey(server_onion_pubkey)
  309. if type(onion_pubkey) is bytes:
  310. onion_pubkey = nacl.public.PublicKey(onion_pubkey)
  311. if onion_pubkey != server_onion_pubkey:
  312. raise ValueError("NTor onion pubkey mismatch")
  313. # We use the blinding keys if present; if they're not present
  314. # (because we're not in Single-Pass Walking Onions), the loops
  315. # are just empty anyway, so everything will work in the usual
  316. # unblinded way.
  317. reblinded_server_ephem_pubkey = server_ephem_pubkey
  318. for blindkey in self.blinding_keys:
  319. reblinded_server_ephem_pubkey = Sphinx.reblindpubkey(blindkey,
  320. reblinded_server_ephem_pubkey, self.perfstats)
  321. xykey = nacl.public.Box(self.client_ephem_key,
  322. reblinded_server_ephem_pubkey).shared_key()
  323. reblinded_onion_pubkey = onion_pubkey
  324. for blindkey in self.blinding_keys:
  325. reblinded_onion_pubkey = Sphinx.reblindpubkey(blindkey,
  326. reblinded_onion_pubkey, self.perfstats)
  327. xbkey = nacl.public.Box(self.client_ephem_key,
  328. reblinded_onion_pubkey).shared_key()
  329. self.perfstats.dhs += 2
  330. M = xykey + xbkey + \
  331. idpubkey + \
  332. onion_pubkey.encode(encoder=nacl.encoding.RawEncoder) + \
  333. server_ephem_pubkey.encode(encoder=nacl.encoding.RawEncoder)
  334. Acheck = nacl.hash.sha256(M + b'verify', encoder=nacl.encoding.RawEncoder)
  335. S = nacl.hash.sha256(M + b'secret', encoder=nacl.encoding.RawEncoder)
  336. if Acheck != authtag:
  337. raise ValueError("NTor auth mismatch")
  338. if sphinx_domainsep is not None:
  339. blindkey = Sphinx.makeblindkey(S, sphinx_domainsep,
  340. self.perfstats)
  341. self.blinding_keys.append(blindkey)
  342. return S
  343. class VanillaExtendCircuitHandler:
  344. """A handler for VanillaExtendCircuitCell cells. It allocates a new
  345. circuit id on the Channel to the requested next hop, connects the
  346. existing and new circuits together, and forwards a
  347. VanillaCreateCircuitMsg to the next hop."""
  348. def received_cell(self, circhandler, cell):
  349. # Remove ourselves from handling a second
  350. # VanillaExtendCircuitCell on this circuit
  351. circhandler.replace_celltype_handler(VanillaExtendCircuitCell, None)
  352. # Allocate a new circuit id to the requested next hop
  353. channelmgr = circhandler.channel.channelmgr
  354. nexthopchannel = channelmgr.get_channel_to(cell.hopaddr)
  355. newcircid, newcirchandler = nexthopchannel.new_circuit()
  356. # Connect the existing and new circuits together
  357. circhandler.adjacent_circuit_handler = newcirchandler
  358. newcirchandler.adjacent_circuit_handler = circhandler
  359. # Set up a handler for when the VanillaCreatedCircuitCell comes
  360. # back
  361. newcirchandler.replace_celltype_handler(
  362. VanillaCreatedCircuitCell,
  363. VanillaCreatedRelayHandler())
  364. # Forward a VanillaCreateCircuitMsg to the next hop
  365. nexthopchannel.send_msg(
  366. VanillaCreateCircuitMsg(newcircid, cell.ntor_request))
  367. class TelescopingExtendCircuitHandler:
  368. """A handler for TelescopingExtendCircuitCell cells. It allocates a new
  369. circuit id on the Channel to the requested next hop, connects the
  370. existing and new circuits together, and forwards a
  371. TelescopingCreateCircuitMsg to the next hop."""
  372. def __init__(self, relaypicker, current_relay_idkey):
  373. self.relaypicker = relaypicker
  374. self.current_relay_idkey = bytes(current_relay_idkey)
  375. def received_cell(self, circhandler, cell):
  376. # Remove ourselves from handling a second
  377. # TelescopingExtendCircuitCell on this circuit
  378. circhandler.replace_celltype_handler(TelescopingExtendCircuitCell, None)
  379. # Find the SNIP corresponding to the index sent by the client
  380. next_snip = self.relaypicker.pick_relay_by_uniform_index(cell.idx)
  381. # Check to make sure that we aren't extending to ourselves. If we are,
  382. # close the circuit.
  383. if next_snip.snipdict["idkey"] == self.current_relay_idkey:
  384. logging.debug("Client requested extending the circuit to a relay already in the path; aborting. my circid: %s", str(circhandler.circid))
  385. circhandler.close()
  386. return
  387. # Allocate a new circuit id to the requested next hop
  388. channelmgr = circhandler.channel.channelmgr
  389. nexthopchannel = channelmgr.get_channel_to(next_snip.snipdict["addr"])
  390. newcircid, newcirchandler = nexthopchannel.new_circuit()
  391. # Connect the existing and new circuits together
  392. circhandler.adjacent_circuit_handler = newcirchandler
  393. newcirchandler.adjacent_circuit_handler = circhandler
  394. # Set up a handler for when the TelescopingCreatedCircuitCell comes
  395. # back
  396. newcirchandler.replace_celltype_handler(
  397. TelescopingCreatedCircuitCell,
  398. TelescopingCreatedRelayHandler(next_snip))
  399. # Forward a TelescopingCreateCircuitMsg to the next hop
  400. nexthopchannel.send_msg(
  401. TelescopingCreateCircuitMsg(newcircid, cell.ntor_request))
  402. class VanillaCreatedRelayHandler:
  403. """Handle a VanillaCreatedCircuitCell received by a _relay_ that
  404. recently received a VanillaExtendCircuitCell from a client, and so
  405. forwarded a VanillaCreateCircuitCell to the next hop."""
  406. def received_cell(self, circhandler, cell):
  407. # Remove ourselves from handling a second
  408. # VanillaCreatedCircuitCell on this circuit
  409. circhandler.replace_celltype_handler(VanillaCreatedCircuitCell, None)
  410. # Just forward a VanillaExtendedCircuitCell back towards the
  411. # client
  412. circhandler.adjacent_circuit_handler.send_cell(
  413. VanillaExtendedCircuitCell(cell.ntor_reply))
  414. class TelescopingCreatedRelayHandler:
  415. """Handle a TelescopingCreatedCircuitCell received by a _relay_ that
  416. recently received a TelescopingExtendCircuitCell from a client, and so
  417. forwarded a TelescopingCreateCircuitCell to the next hop."""
  418. def __init__(self, next_snip):
  419. self.next_snip = next_snip
  420. def received_cell(self, circhandler, cell):
  421. logging.debug("Handle a TelescopingCreatedCircuit received by a relay")
  422. # Remove ourselves from handling a second
  423. # TelescopingCreatedCircuitCell on this circuit
  424. circhandler.replace_celltype_handler(TelescopingCreatedCircuitCell, None)
  425. # Just forward a TelescopingExtendedCircuitCell back towards the
  426. # client
  427. circhandler.adjacent_circuit_handler.send_cell(
  428. TelescopingExtendedCircuitCell(cell.ntor_reply, self.next_snip))
  429. class SinglePassCreatedRelayHandler:
  430. """Handle a SinglePassCreatedCircuitCell received by a _relay_ that
  431. recently received a SinglePassCreateCircuitMsg from this relay."""
  432. def __init__(self, ntorreply, next_snip, vrf_output, ttl):
  433. self.ntorreply = ntorreply
  434. self.next_snip = next_snip
  435. self.vrf_output = vrf_output
  436. self.ttl = ttl
  437. def received_cell(self, circhandler, cell):
  438. logging.debug("Handle a SinglePassCreatedCircuitCell received by a relay, my ttl is %s", str(self.ttl))
  439. # Remove ourselves from handling a second
  440. # SinglePassCreatedCircuitCell on this circuit
  441. circhandler.replace_celltype_handler(SinglePassCreatedCircuitCell, None)
  442. logging.debug("Sending a SinglePassCreatedCell after receiving one from %s; my ttl is %s", self.next_snip.snipdict['addr'], str(self.ttl))
  443. # Just forward a SinglePassCreatedCircuitCell back towards the
  444. # client
  445. circhandler.adjacent_circuit_handler.channel_send_cell(
  446. SinglePassCreatedCircuitCell(cell.ntor_reply, self.next_snip,
  447. self.vrf_output, self.ttl, cell))
  448. class CircuitHandler:
  449. """A class for managing sending and receiving encrypted cells on a
  450. particular circuit."""
  451. class NoCryptLayer:
  452. def encrypt_msg(self, msg): return msg
  453. def decrypt_msg(self, msg): return msg
  454. class CryptLayer:
  455. def __init__(self, enckey, deckey, next_layer):
  456. self.enckey = enckey
  457. self.deckey = deckey
  458. self.next_layer = next_layer
  459. def encrypt_msg(self, msg):
  460. return self.next_layer.encrypt_msg(EncryptedCell(self.enckey, msg))
  461. def decrypt_msg(self, msg):
  462. return self.next_layer.decrypt_msg(msg).decrypt(self.deckey)
  463. def __init__(self, channel, circid):
  464. self.channel = channel
  465. self.circid = circid
  466. # The list of relay descriptors that form the circuit so far
  467. # (client side only)
  468. self.circuit_descs = []
  469. # The dispatch table is indexed by type, and the values are
  470. # objects with received_cell(circhandler, cell) methods.
  471. self.cell_dispatch_table = dict()
  472. # The topmost crypt layer. This is an object with
  473. # encrypt_msg(msg) and decrypt_msg(msg) methods that returns the
  474. # en/decrypted messages respectively. Messages are encrypted
  475. # starting with the last layer that was added (the keys for the
  476. # furthest away relay in the circuit) and are decrypted starting
  477. # with the first layer that was added (the keys for the guard).
  478. self.crypt_layer = self.NoCryptLayer()
  479. # The adjacent CircuitHandler that's connected to this one. If
  480. # we get a cell on one, we forward it to the other (if it's not
  481. # meant for us to handle directly)
  482. self.adjacent_circuit_handler = None
  483. # The function to call when this circuit closes
  484. self.closer = lambda: self.channel.circuithandlers.pop(circid)
  485. def close(self):
  486. """Close the circuit. Sends a CloseCell on the circuit (and its
  487. adjacent circuit, if present) and closes both."""
  488. adjcirchandler = self.adjacent_circuit_handler
  489. self.adjacent_circuit_handler = None
  490. logging.debug("Closing circuit. circid: %s", str(self.circid))
  491. if adjcirchandler is not None:
  492. adjcirchandler.adjacent_circuit_handler = None
  493. self.closer()
  494. self.channel_send_cell(CloseCell())
  495. if adjcirchandler is not None:
  496. adjcirchandler.closer()
  497. adjcirchandler.channel_send_cell(CloseCell())
  498. def send_cell(self, cell):
  499. """Send a cell on this circuit, encrypting as needed."""
  500. self.channel_send_cell(self.crypt_layer.encrypt_msg(cell))
  501. def channel_send_cell(self, cell):
  502. """Send a cell on this circuit directly without encrypting it
  503. first."""
  504. self.channel.send_msg(CircuitCellMsg(self.circid, cell))
  505. def received_cell(self, cell):
  506. """A cell has been received on this circuit. Dispatch it
  507. according to its type."""
  508. if isinstance(cell, EncryptedCell):
  509. cell = self.crypt_layer.decrypt_msg(cell)
  510. logging.debug("CircuitHandler: %s received cell %s on circuit %d from %s" % (self.channel.channelmgr.myaddr, cell, self.circid, self.channel.peer.channelmgr.myaddr))
  511. # If it's still encrypted, it's for sure meant for forwarding to
  512. # our adjacent hop, which had better exist.
  513. if isinstance(cell, EncryptedCell):
  514. self.adjacent_circuit_handler.send_cell(cell)
  515. else:
  516. # This is a plaintext cell meant for us. Handle it
  517. # according to the table.
  518. celltype = type(cell)
  519. if celltype in self.cell_dispatch_table:
  520. self.cell_dispatch_table[celltype].received_cell(self, cell)
  521. elif isinstance(cell, StringCell):
  522. # Default handler; just print the message in the cell
  523. logging.debug("CircuitHandler: %s received '%s' on circuit %d from %s" \
  524. % (self.channel.channelmgr.myaddr, cell,
  525. self.circid, self.channel.peer.channelmgr.myaddr))
  526. elif isinstance(cell, CloseCell):
  527. logging.debug("Received CloseCell on circuit %s", str(self.circid))
  528. # Forward the CloseCell (without encryption) to the
  529. # adjacent circuit, if any, and close both this and the
  530. # adjacent circuit
  531. adjcirchandler = self.adjacent_circuit_handler
  532. self.adjacent_circuit_handler = None
  533. if adjcirchandler is not None:
  534. adjcirchandler.adjacent_circuit_handler = None
  535. self.closer()
  536. if adjcirchandler is not None:
  537. adjcirchandler.closer()
  538. adjcirchandler.channel_send_cell(cell)
  539. else:
  540. # I don't know how to handle this cell?
  541. raise ValueError("CircuitHandler: %s received unknown cell type %s on circuit %d from %s" \
  542. % (self.channel.channelmgr.myaddr, cell,
  543. self.circid, self.channel.peer.channelmgr.myaddr))
  544. def replace_celltype_handler(self, celltype, handler):
  545. """Add an object with a received_cell(circhandler, cell) method
  546. to the cell dispatch table. It replaces anything that's already
  547. there. Passing None as the handler removes the dispatcher for
  548. that cell type."""
  549. if handler is None:
  550. del self.cell_dispatch_table[celltype]
  551. else:
  552. self.cell_dispatch_table[celltype] = handler
  553. def add_crypt_layer(self, enckey, deckey):
  554. """Add a processing layer to this CircuitHandler so that cells
  555. we send will get encrypted with the first given key, and cells
  556. we receive will be decrypted with the other given key."""
  557. current_crypt_layer = self.crypt_layer
  558. self.crypt_layer = self.CryptLayer(enckey, deckey, current_crypt_layer)
  559. class Channel(network.Connection):
  560. """A class representing a channel between a relay and either a
  561. client or a relay, transporting cells from various circuits."""
  562. def __init__(self):
  563. super().__init__()
  564. # The RelayChannelManager managing this Channel
  565. self.channelmgr = None
  566. # The Channel at the other end
  567. self.peer = None
  568. # The function to call when the connection closes
  569. self.closer = lambda: None
  570. # The next circuit id to use on this channel. The party that
  571. # opened the channel uses even numbers; the receiving party uses
  572. # odd numbers.
  573. self.next_circid = None
  574. # A map for CircuitHandlers to use for each open circuit on the
  575. # channel
  576. self.circuithandlers = dict()
  577. def closed(self):
  578. # Close each circuithandler we're managing
  579. while self.circuithandlers:
  580. chitems = iter(self.circuithandlers.items())
  581. circid, circhandler = next(chitems)
  582. logging.debug('closing circuit %s', circid)
  583. circhandler.close()
  584. self.closer()
  585. self.peer = None
  586. def close(self):
  587. peer = self.peer
  588. self.closed()
  589. if peer is not None and peer is not self:
  590. peer.closed()
  591. def new_circuit(self):
  592. """Allocate a new circuit on this channel, returning the new
  593. circuit's id and the new CircuitHandler."""
  594. circid = self.next_circid
  595. self.next_circid += 2
  596. circuithandler = CircuitHandler(self, circid)
  597. self.circuithandlers[circid] = circuithandler
  598. return circid, circuithandler
  599. def is_circuit_open(self, circid):
  600. is_open = (circid in self.circuithandlers) and (self.circuithandlers[circid] is not None)
  601. return is_open
  602. def new_circuit_with_circid(self, circid):
  603. """Allocate a new circuit on this channel, with the circuit id
  604. received from our peer. Return the new CircuitHandler"""
  605. circuithandler = CircuitHandler(self, circid)
  606. self.circuithandlers[circid] = circuithandler
  607. return circuithandler
  608. def send_cell(self, circid, cell):
  609. """Send the given message on the given circuit, encrypting or
  610. decrypting as needed."""
  611. self.circuithandlers[circid].send_cell(cell)
  612. def send_raw_cell(self, circid, cell):
  613. """Send the given message, tagged for the given circuit id. No
  614. encryption or decryption is done."""
  615. self.send_msg(CircuitCellMsg(self.circid, self.cell))
  616. def send_msg(self, msg):
  617. """Send the given NetMsg on the channel."""
  618. self.channelmgr.perfstats.bytes_sent += msg.size()
  619. self.peer.received(self.channelmgr.myaddr, msg)
  620. def received(self, peeraddr, msg):
  621. """Callback when a message is received from the network."""
  622. logging.debug('Channel: %s received %s from %s' % (self.channelmgr.myaddr, msg, peeraddr))
  623. self.channelmgr.perfstats.bytes_received += msg.size()
  624. if isinstance(msg, CircuitCellMsg):
  625. circid, cell = msg.circid, msg.cell
  626. self.circuithandlers[circid].received_cell(cell)
  627. else:
  628. self.channelmgr.received_msg(msg, peeraddr, self)
  629. class ChannelManager:
  630. """The class that manages the channels to other relays and clients.
  631. Relays and clients both use subclasses of this class to both create
  632. on-demand channels to relays, to gracefully handle the closing of
  633. channels, and to handle commands received over the channels."""
  634. def __init__(self, myaddr, dirauthaddrs, perfstats):
  635. # A dictionary of Channels to other hosts, indexed by NetAddr
  636. self.channels = dict()
  637. self.myaddr = myaddr
  638. self.dirauthaddrs = dirauthaddrs
  639. self.consensus = None
  640. self.relaypicker = None
  641. self.perfstats = perfstats
  642. def terminate(self):
  643. """Close all connections we're managing."""
  644. while self.channels:
  645. channelitems = iter(self.channels.items())
  646. addr, channel = next(channelitems)
  647. logging.debug('closing channel %s %s', addr, channel)
  648. channel.close()
  649. def add_channel(self, channel, peeraddr):
  650. """Add the given channel to the list of channels we are
  651. managing. If we are already managing a channel to the same
  652. peer, close it first."""
  653. if peeraddr in self.channels:
  654. self.channels[peeraddr].close()
  655. channel.channelmgr = self
  656. self.channels[peeraddr] = channel
  657. channel.closer = lambda: self.channels.pop(peeraddr)
  658. def get_channel_to(self, addr):
  659. """Get the Channel connected to the given NetAddr, creating one
  660. if none exists right now."""
  661. if addr in self.channels:
  662. return self.channels[addr]
  663. # Create the new channel
  664. logging.debug('getting channel from %s to %s',self.myaddr,addr)
  665. newchannel = network.thenetwork.connect(self.myaddr, addr,
  666. self.perfstats)
  667. logging.debug('got channel from %s to %s',self.myaddr,addr)
  668. self.channels[addr] = newchannel
  669. newchannel.closer = lambda: self.channels.pop(addr)
  670. newchannel.channelmgr = self
  671. return newchannel
  672. def received_msg(self, msg, peeraddr, channel):
  673. """Callback when a NetMsg not specific to a circuit is
  674. received."""
  675. logging.debug("ChannelManager: Node %s received msg %s from %s" % (self.myaddr, msg, peeraddr))
  676. def received_cell(self, circid, cell, peeraddr, channel):
  677. """Callback with a circuit-specific cell is received."""
  678. logging.debug("ChannelManager: Node %s received cell on circ %d: %s from %s" % (self.myaddr, circid, cell, peeraddr))
  679. def send_msg(self, msg, peeraddr):
  680. """Send a message to the peer with the given address."""
  681. channel = self.get_channel_to(peeraddr)
  682. channel.send_msg(msg)
  683. def send_cell(self, circid, cell, peeraddr):
  684. """Send a cell on the given circuit to the peer with the given
  685. address."""
  686. channel = self.get_channel_to(peeraddr)
  687. channel.send_cell(circid, cell)
  688. class RelayChannelManager(ChannelManager):
  689. """The subclass of ChannelManager for relays."""
  690. def __init__(self, myaddr, dirauthaddrs, onionprivkey, idpubkey,
  691. path_selection_key, perfstats):
  692. super().__init__(myaddr, dirauthaddrs, perfstats)
  693. self.onionkey = onionprivkey
  694. self.idpubkey = idpubkey
  695. if network.thenetwork.womode != network.WOMode.VANILLA:
  696. self.endive = None
  697. if network.thenetwork.womode == network.WOMode.SINGLEPASS:
  698. self.path_selection_key = path_selection_key
  699. def get_consensus(self):
  700. """Download a fresh consensus (and ENDIVE if using Walking
  701. Onions) from a random dirauth."""
  702. a = random.choice(self.dirauthaddrs)
  703. c = network.thenetwork.connect(self, a, self.perfstats)
  704. if network.thenetwork.womode == network.WOMode.VANILLA:
  705. if self.consensus is not None and \
  706. len(self.consensus.consdict['relays']) > 0:
  707. self.consensus = c.getconsensusdiff()
  708. else:
  709. self.consensus = c.getconsensus()
  710. self.relaypicker = dirauth.Consensus.verify(self.consensus,
  711. network.thenetwork.dirauthkeys(), self.perfstats)
  712. else:
  713. self.consensus = c.getconsensus()
  714. if self.endive is not None and \
  715. len(self.endive.enddict['snips']) > 0:
  716. self.endive = c.getendivediff()
  717. else:
  718. self.endive = c.getendive()
  719. self.relaypicker = dirauth.ENDIVE.verify(self.endive,
  720. self.consensus, network.thenetwork.dirauthkeys(),
  721. self.perfstats)
  722. c.close()
  723. def received_msg(self, msg, peeraddr, channel):
  724. """Callback when a NetMsg not specific to a circuit is
  725. received."""
  726. logging.debug("RelayChannelManager: Node %s received msg %s from %s" % (self.myaddr, msg, peeraddr))
  727. if isinstance(msg, RelayRandomHopMsg):
  728. if msg.ttl > 0:
  729. # Pick a random next hop from the consensus
  730. nexthop = self.relaypicker.pick_weighted_relay()
  731. if network.thenetwork.womode == network.WOMode.VANILLA:
  732. nextaddr = nexthop.descdict["addr"]
  733. else:
  734. nextaddr = nexthop.snipdict["addr"]
  735. self.send_msg(RelayRandomHopMsg(msg.ttl-1), nextaddr)
  736. elif isinstance(msg, RelayGetConsensusMsg):
  737. self.send_msg(RelayConsensusMsg(self.consensus), peeraddr)
  738. elif isinstance(msg, RelayGetConsensusDiffMsg):
  739. self.send_msg(RelayConsensusDiffMsg(self.consensus), peeraddr)
  740. elif isinstance(msg, VanillaCreateCircuitMsg):
  741. # A new circuit has arrived
  742. circhandler = channel.new_circuit_with_circid(msg.circid)
  743. # Create the ntor reply
  744. reply, secret = NTor.reply(self.onionkey, self.idpubkey,
  745. msg.ntor_request, self.perfstats)
  746. # Set up the circuit to use the shared secret
  747. enckey = nacl.hash.sha256(secret + b'downstream')
  748. deckey = nacl.hash.sha256(secret + b'upstream')
  749. circhandler.add_crypt_layer(enckey, deckey)
  750. # Add a handler for if an Extend Cell arrives (there should
  751. # be at most one on this circuit).
  752. circhandler.replace_celltype_handler(
  753. VanillaExtendCircuitCell, VanillaExtendCircuitHandler())
  754. # Send the ntor reply
  755. self.send_msg(CircuitCellMsg(msg.circid,
  756. VanillaCreatedCircuitCell(reply)), peeraddr)
  757. elif isinstance(msg, TelescopingCreateCircuitMsg):
  758. # A new circuit has arrived
  759. circhandler = channel.new_circuit_with_circid(msg.circid)
  760. # Create the ntor reply
  761. reply, secret = NTor.reply(self.onionkey, self.idpubkey,
  762. msg.ntor_request, self.perfstats)
  763. # Set up the circuit to use the shared secret
  764. enckey = nacl.hash.sha256(secret + b'downstream')
  765. deckey = nacl.hash.sha256(secret + b'upstream')
  766. circhandler.add_crypt_layer(enckey, deckey)
  767. # Add a handler for if an Extend Cell arrives (there should
  768. # be at most one on this circuit).
  769. circhandler.replace_celltype_handler(
  770. TelescopingExtendCircuitCell,
  771. TelescopingExtendCircuitHandler(self.relaypicker,
  772. self.idpubkey))
  773. # Send the ntor reply
  774. self.send_msg(CircuitCellMsg(msg.circid,
  775. TelescopingCreatedCircuitCell(reply)), peeraddr)
  776. elif isinstance(msg, SinglePassCreateCircuitMsg) and msg.ttl == 0:
  777. # we are the end of the circuit, just establish a shared key and
  778. # return
  779. logging.debug("RelayChannelManager: Single-Pass TTL is 0, replying without extending")
  780. # A new circuit has arrived
  781. circhandler = channel.new_circuit_with_circid(msg.circid)
  782. # Create the ntor reply
  783. reply, secret = NTor.reply(self.onionkey, self.idpubkey,
  784. msg.ntor_request, self.perfstats)
  785. # Set up the circuit to use the shared secret
  786. enckey = nacl.hash.sha256(secret + b'downstream')
  787. deckey = nacl.hash.sha256(secret + b'upstream')
  788. circhandler.add_crypt_layer(enckey, deckey)
  789. # Send the ntor reply, but no need to send the snip for the next
  790. # relay or vrf proof, as this is the last relay in the circuit.
  791. self.send_msg(CircuitCellMsg(msg.circid,
  792. SinglePassCreatedCircuitCell(reply, None, None, 0, None)), peeraddr)
  793. elif isinstance(msg, SinglePassCreateCircuitMsg) and msg.ttl > 0:
  794. logging.debug("RelayChannelManager: Single-Pass TTL is greater than 0; extending")
  795. # A new circuit has arrived
  796. circhandler = channel.new_circuit_with_circid(msg.circid)
  797. # Create the ntor reply for the circuit-extension key, and derive
  798. # the client's next blinded key
  799. (ntorreply, secret), blinded_client_encr_key = NTor.reply(self.onionkey, self.idpubkey,
  800. msg.ntor_request, self.perfstats, b'circuit')
  801. # Set up the circuit to use the shared secret established from the
  802. # circuit extension key
  803. enckey = nacl.hash.sha256(secret + b'downstream')
  804. deckey = nacl.hash.sha256(secret + b'upstream')
  805. circhandler.add_crypt_layer(enckey, deckey)
  806. # here, we will directly extend the circuit ourselves, after
  807. # determining the next relay using the client's path selection
  808. # key in conjunction with our own
  809. idx_as_hex, blinded_client_path_selection_key = Sphinx.server(msg.client_path_selection_key,
  810. self.path_selection_key, b'circuit', False, self.perfstats)
  811. logging.debug("RelayChannelManager: Unimplemented! need to translate idx into endive index")
  812. logging.debug("RelayChannelManager: Unimplemented! need to pick the next relay using the shared secret between the client and the relay.")
  813. # simpulate the VRF output for now
  814. vrf_output = VRF(self.path_selection_key,
  815. self.relaypicker).get_output(idx_as_hex)
  816. next_hop = self.relaypicker.pick_relay_by_uniform_index(vrf_output.output)
  817. if next_hop == None:
  818. logging.debug("Client requested extending the circuit to a relay index that results in None, aborting. my circid: %s", str(circhandler.circid))
  819. circhandler.close()
  820. elif next_hop.snipdict["idkey"] == bytes(self.idpubkey) or next_hop.snipdict["addr"] == peeraddr:
  821. logging.debug("Client requested extending the circuit to a relay already in the path; aborting. my circid: %s", str(circhandler.circid))
  822. circhandler.close()
  823. # Allocate a new circuit id to the requested next hop
  824. channelmgr = circhandler.channel.channelmgr
  825. nexthopchannel = channelmgr.get_channel_to(next_hop.snipdict["addr"])
  826. newcircid, newcirchandler = nexthopchannel.new_circuit()
  827. # Connect the existing and new circuits together
  828. circhandler.adjacent_circuit_handler = newcirchandler
  829. newcirchandler.adjacent_circuit_handler = circhandler
  830. # Add a handler for once the next relay replies to say that the
  831. # circuit has been created
  832. newcirchandler.replace_celltype_handler(
  833. SinglePassCreatedCircuitCell,
  834. SinglePassCreatedRelayHandler(ntorreply, next_hop,
  835. vrf_output, msg.ttl))
  836. # Send the next create message to the next hop
  837. nexthopchannel.send_msg(SinglePassCreateCircuitMsg(newcircid,
  838. blinded_client_encr_key, blinded_client_path_selection_key,
  839. msg.ttl-1))
  840. else:
  841. return super().received_msg(msg, peeraddr, channel)
  842. def received_cell(self, circid, cell, peeraddr, channel):
  843. """Callback with a circuit-specific cell is received."""
  844. logging.debug("RelayChannelManager: Node %s received cell on circ %d: %s from %s" % (self.myaddr, circid, cell, peeraddr))
  845. return super().received_cell(circid, cell, peeraddr, channel)
  846. class Relay(network.Server):
  847. """The class representing an onion relay."""
  848. def __init__(self, dirauthaddrs, bw, flags):
  849. # Gather performance statistics
  850. self.perfstats = network.PerfStats(network.EntType.RELAY, bw)
  851. self.perfstats.is_bootstrapping = True
  852. # Create the identity and onion keys
  853. self.idkey = nacl.signing.SigningKey.generate()
  854. self.onionkey = nacl.public.PrivateKey.generate()
  855. self.perfstats.keygens += 2
  856. self.name = self.idkey.verify_key.encode(encoder=nacl.encoding.HexEncoder).decode("ascii")
  857. # Bind to the network to get a network address
  858. self.netaddr = network.thenetwork.bind(self)
  859. self.perfstats.name = "Relay at %s" % self.netaddr
  860. # Our bandwidth and flags
  861. self.bw = bw
  862. self.flags = flags
  863. # Register for epoch change notification
  864. network.thenetwork.wantepochticks(self, True, end=True)
  865. network.thenetwork.wantepochticks(self, True)
  866. if network.thenetwork.womode == network.WOMode.SINGLEPASS:
  867. self.path_selection_key = nacl.public.PrivateKey.generate()
  868. else:
  869. self.path_selection_key = None
  870. # Create the RelayChannelManager connection manager
  871. self.channelmgr = RelayChannelManager(self.netaddr, dirauthaddrs,
  872. self.onionkey, self.idkey.verify_key, self.path_selection_key, self.perfstats)
  873. # Initially, we're not a fallback relay
  874. self.is_fallbackrelay = False
  875. self.uploaddesc()
  876. def terminate(self):
  877. """Stop this relay."""
  878. if self.is_fallbackrelay:
  879. # Fallback relays must not (for now) terminate
  880. raise RelayFallbackTerminationError(self)
  881. # Stop listening for epoch ticks
  882. network.thenetwork.wantepochticks(self, False, end=True)
  883. network.thenetwork.wantepochticks(self, False)
  884. # Tell the dirauths we're going away
  885. self.uploaddesc(False)
  886. # Close connections to other relays
  887. self.channelmgr.terminate()
  888. # Stop listening to our own bound port
  889. self.close()
  890. def set_is_fallbackrelay(self, isfallback = True):
  891. """Set this relay to be a fallback relay (or unset if passed
  892. False)."""
  893. self.is_fallbackrelay = isfallback
  894. def epoch_ending(self, epoch):
  895. # Download the new consensus, which will have been created
  896. # already since the dirauths' epoch_ending callbacks happened
  897. # before the relays'.
  898. self.channelmgr.get_consensus()
  899. def newepoch(self, epoch):
  900. self.uploaddesc()
  901. def uploaddesc(self, upload=True):
  902. # Upload the descriptor for the epoch to come, or delete a
  903. # previous upload if upload=False
  904. descdict = dict();
  905. descdict["epoch"] = network.thenetwork.getepoch() + 1
  906. descdict["idkey"] = bytes(self.idkey.verify_key)
  907. descdict["onionkey"] = bytes(self.onionkey.public_key)
  908. descdict["addr"] = self.netaddr
  909. descdict["bw"] = self.bw
  910. descdict["flags"] = self.flags
  911. if network.thenetwork.womode == network.WOMode.SINGLEPASS:
  912. descdict["path_selection_key"] = self.path_selection_key
  913. desc = dirauth.RelayDescriptor(descdict)
  914. desc.sign(self.idkey, self.perfstats)
  915. dirauth.RelayDescriptor.verify(desc, self.perfstats)
  916. if upload:
  917. descmsg = dirauth.DirAuthUploadDescMsg(desc)
  918. else:
  919. # Note that this relies on signatures being deterministic;
  920. # otherwise we'd need to save the descriptor we uploaded
  921. # before so we could tell the airauths to delete the exact
  922. # one
  923. descmsg = dirauth.DirAuthDelDescMsg(desc)
  924. # Upload them
  925. for a in self.channelmgr.dirauthaddrs:
  926. c = network.thenetwork.connect(self, a, self.perfstats)
  927. c.sendmsg(descmsg)
  928. c.close()
  929. def connected(self, peer):
  930. """Callback invoked when someone (client or relay) connects to
  931. us. Create a pair of linked Channels and return the peer half
  932. to the peer."""
  933. # Create the linked pair
  934. if peer is self.netaddr:
  935. # A self-loop? We'll allow it.
  936. peerchannel = Channel()
  937. peerchannel.peer = peerchannel
  938. peerchannel.next_circid = 2
  939. return peerchannel
  940. peerchannel = Channel()
  941. ourchannel = Channel()
  942. peerchannel.peer = ourchannel
  943. peerchannel.next_circid = 2
  944. ourchannel.peer = peerchannel
  945. ourchannel.next_circid = 1
  946. # Add our channel to the RelayChannelManager
  947. self.channelmgr.add_channel(ourchannel, peer)
  948. return peerchannel
  949. if __name__ == '__main__':
  950. perfstats = network.PerfStats(network.EntType.NONE)
  951. # Initialize the (non-cryptographic) random seed
  952. random.seed(1)
  953. if len(sys.argv) < 3:
  954. print("Must pass in network mode and snip auth mode!")
  955. print("Network options are vanilla, telescoping, or single-pass.")
  956. print("SNIP auth options are merkle or threshold.")
  957. sys.exit(0)
  958. network_mode = network.WOMode.string_to_type(sys.argv[1])
  959. if network_mode == -1:
  960. print("Not a valid network mode: " + network_mode)
  961. sys.exit(0)
  962. snipauth_mode = network.SNIPAuthMode.string_to_type(sys.argv[2])
  963. if network_mode == -1:
  964. print("Not a valid SNIP authentication mode: " + snipauth_mode)
  965. sys.exit(0)
  966. if network_mode == network.WOMode.VANILLA:
  967. network.thenetwork.set_wo_style(network.WOMode.VANILLA,
  968. network.SNIPAuthMode.NONE)
  969. elif network_mode == network.WOMode.TELESCOPING:
  970. if snipauth_mode == network.SNIPAuthMode.MERKLE:
  971. network.thenetwork.set_wo_style(network.WOMode.TELESCOPING,
  972. network.SNIPAuthMode.MERKLE)
  973. else:
  974. network.thenetwork.set_wo_style(network.WOMode.TELESCOPING,
  975. network.SNIPAuthMode.THRESHSIG)
  976. elif network_mode == network.WOMode.SINGLEPASS:
  977. if snipauth_mode == network.SNIPAuthMode.MERKLE:
  978. network.thenetwork.set_wo_style(network.WOMode.SINGLEPASS,
  979. network.SNIPAuthMode.MERKLE)
  980. else:
  981. network.thenetwork.set_wo_style(network.WOMode.SINGLEPASS,
  982. network.SNIPAuthMode.THRESHSIG)
  983. else:
  984. sys.exit("Received unsupported network mode, exiting.")
  985. # Start some dirauths
  986. numdirauths = 9
  987. dirauthaddrs = []
  988. for i in range(numdirauths):
  989. dira = dirauth.DirAuth(i, numdirauths)
  990. dirauthaddrs.append(dira.netaddr)
  991. # Start some relays
  992. numrelays = 10
  993. relays = []
  994. for i in range(numrelays):
  995. # Relay bandwidths (at least the ones fast enough to get used)
  996. # in the live Tor network (as of Dec 2019) are well approximated
  997. # by (200000-(200000-25000)/3*log10(x)) where x is a
  998. # uniform integer in [1,2500]
  999. x = random.randint(1,2500)
  1000. bw = int(200000-(200000-25000)/3*math.log10(x))
  1001. relays.append(Relay(dirauthaddrs, bw, 0))
  1002. # The fallback relays are a hardcoded list of about 5% of the
  1003. # relays, used by clients for bootstrapping
  1004. numfallbackrelays = int(numrelays * 0.05) + 1
  1005. fallbackrelays = random.sample(relays, numfallbackrelays)
  1006. for r in fallbackrelays:
  1007. r.set_is_fallbackrelay()
  1008. network.thenetwork.setfallbackrelays(fallbackrelays)
  1009. # Tick the epoch
  1010. network.thenetwork.nextepoch()
  1011. print(dirauth.DirAuth.consensus)
  1012. print(dirauth.DirAuth.endive)
  1013. if network.thenetwork.womode == network.WOMode.VANILLA:
  1014. relaypicker = dirauth.Consensus.verify(dirauth.DirAuth.consensus,
  1015. network.thenetwork.dirauthkeys(), perfstats)
  1016. else:
  1017. relaypicker = dirauth.ENDIVE.verify(dirauth.DirAuth.endive,
  1018. dirauth.DirAuth.consensus,
  1019. network.thenetwork.dirauthkeys(), perfstats)
  1020. if network.thenetwork.snipauthmode == \
  1021. network.SNIPAuthMode.THRESHSIG:
  1022. for s in dirauth.DirAuth.endive.enddict['snips']:
  1023. dirauth.SNIP.verify(s, dirauth.DirAuth.consensus,
  1024. network.thenetwork.dirauthkeys()[0], perfstats)
  1025. print('ticked; epoch=', network.thenetwork.getepoch())
  1026. relays[3].channelmgr.send_msg(RelayRandomHopMsg(30), relays[5].netaddr)
  1027. # See what channels exist and do a consistency check
  1028. for r in relays:
  1029. print("%s: %s" % (r.netaddr, [ str(k) for k in r.channelmgr.channels.keys()]))
  1030. raddr = r.netaddr
  1031. for ad, ch in r.channelmgr.channels.items():
  1032. if ch.peer.channelmgr.myaddr != ad:
  1033. print('address mismatch:', raddr, ad, ch.peer.channelmgr.myaddr)
  1034. if ch.peer.channelmgr.channels[raddr].peer is not ch:
  1035. print('asymmetry:', raddr, ad, ch, ch.peer.channelmgr.channels[raddr].peer)
  1036. # Stop some relays
  1037. relays[3].terminate()
  1038. del relays[3]
  1039. relays[5].terminate()
  1040. del relays[5]
  1041. relays[7].terminate()
  1042. del relays[7]
  1043. # Tick the epoch
  1044. network.thenetwork.nextepoch()
  1045. print(dirauth.DirAuth.consensus)
  1046. print(dirauth.DirAuth.endive)
  1047. # See what channels exist and do a consistency check
  1048. for r in relays:
  1049. print("%s: %s" % (r.netaddr, [ str(k) for k in r.channelmgr.channels.keys()]))
  1050. raddr = r.netaddr
  1051. for ad, ch in r.channelmgr.channels.items():
  1052. if ch.peer.channelmgr.myaddr != ad:
  1053. print('address mismatch:', raddr, ad, ch.peer.channelmgr.myaddr)
  1054. if ch.peer.channelmgr.channels[raddr].peer is not ch:
  1055. print('asymmetry:', raddr, ad, ch, ch.peer.channelmgr.channels[raddr].peer)
  1056. channel = relays[3].channelmgr.get_channel_to(relays[5].netaddr)
  1057. circid, circhandler = channel.new_circuit()
  1058. peerchannel = relays[5].channelmgr.get_channel_to(relays[3].netaddr)
  1059. peerchannel.new_circuit_with_circid(circid)
  1060. relays[3].channelmgr.send_cell(circid, StringCell("test"), relays[5].netaddr)
  1061. idpubkey = relays[1].idkey.verify_key
  1062. onionpubkey = relays[1].onionkey.public_key
  1063. nt = NTor(perfstats)
  1064. req = nt.request()
  1065. R, S = NTor.reply(relays[1].onionkey, idpubkey, req, perfstats)
  1066. S2 = nt.verify(R, onionpubkey, idpubkey)
  1067. print(S == S2)
  1068. # Test the Sphinx class: DH version (for the path selection keys)
  1069. server1_key = nacl.public.PrivateKey.generate()
  1070. server2_key = nacl.public.PrivateKey.generate()
  1071. server3_key = nacl.public.PrivateKey.generate()
  1072. client_key = nacl.public.PrivateKey.generate()
  1073. # Check that normal DH is working
  1074. ckey = nacl.public.Box(client_key, server1_key.public_key).shared_key()
  1075. skey = nacl.public.Box(server1_key, client_key.public_key).shared_key()
  1076. assert(ckey == skey)
  1077. # Transform the client pubkey with Sphinx as it passes through the
  1078. # servers and record the resulting shared secrets
  1079. blinded_client_pubkey = client_key.public_key
  1080. s1secret, blinded_client_pubkey = Sphinx.server(blinded_client_pubkey,
  1081. server1_key, b'circuit', False, perfstats)
  1082. s2secret, blinded_client_pubkey = Sphinx.server(blinded_client_pubkey,
  1083. server2_key, b'circuit', False, perfstats)
  1084. s3secret, _ = Sphinx.server(blinded_client_pubkey,
  1085. server3_key, b'circuit', True, perfstats)
  1086. # Hopefully matching keys on the client side
  1087. blinding_keys = []
  1088. c1secret, blind_key = Sphinx.client(client_key, blinding_keys,
  1089. server1_key.public_key, b'circuit', False, perfstats)
  1090. blinding_keys.append(blind_key)
  1091. c2secret, blind_key = Sphinx.client(client_key, blinding_keys,
  1092. server2_key.public_key, b'circuit', False, perfstats)
  1093. blinding_keys.append(blind_key)
  1094. c3secret, _ = Sphinx.client(client_key, blinding_keys,
  1095. server3_key.public_key, b'circuit', True, perfstats)
  1096. assert(s1secret == c1secret)
  1097. assert(s2secret == c2secret)
  1098. assert(s3secret == c3secret)
  1099. print('Sphinx DH test successful')
  1100. # End test of Sphinx (DH version)
  1101. # Test the Sphinx class: NTor version (for the path selection keys)
  1102. server1_idkey = nacl.signing.SigningKey.generate().verify_key
  1103. server2_idkey = nacl.signing.SigningKey.generate().verify_key
  1104. server3_idkey = nacl.signing.SigningKey.generate().verify_key
  1105. server1_onionkey = nacl.public.PrivateKey.generate()
  1106. server2_onionkey = nacl.public.PrivateKey.generate()
  1107. server3_onionkey = nacl.public.PrivateKey.generate()
  1108. client_ntor = NTor(perfstats)
  1109. # Client's initial message
  1110. client_pubkey = client_ntor.request()
  1111. # Transform the client pubkey with Sphinx as it passes through the
  1112. # servers and record the resulting shared secrets
  1113. blinded_client_pubkey = client_pubkey
  1114. (s1reply, s1secret), blinded_client_pubkey = NTor.reply(
  1115. server1_onionkey, server1_idkey, blinded_client_pubkey,
  1116. perfstats, b'data')
  1117. (s2reply, s2secret), blinded_client_pubkey = NTor.reply(
  1118. server2_onionkey, server2_idkey, blinded_client_pubkey,
  1119. perfstats, b'data')
  1120. (s3reply, s3secret) = NTor.reply(
  1121. server3_onionkey, server3_idkey, blinded_client_pubkey,
  1122. perfstats)
  1123. # Hopefully matching keys on the client side
  1124. c1secret = client_ntor.verify(s1reply, server1_onionkey.public_key,
  1125. server1_idkey, b'data')
  1126. c2secret = client_ntor.verify(s2reply, server2_onionkey.public_key,
  1127. server2_idkey, b'data')
  1128. c3secret = client_ntor.verify(s3reply, server3_onionkey.public_key,
  1129. server3_idkey)
  1130. assert(s1secret == c1secret)
  1131. assert(s2secret == c2secret)
  1132. assert(s3secret == c3secret)
  1133. print('Sphinx NTor test successful')
  1134. # End test of Sphinx (NTor version)