relay.py 60 KB

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