makedesc.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/python
  2. # Copyright 2014-2015, The Tor Project, Inc.
  3. # See LICENSE for license information
  4. # This is a kludgey python script that uses ctypes and openssl to sign
  5. # router descriptors and extrainfo documents and put all the keys in
  6. # the right places. There are examples at the end of the file.
  7. # I've used this to make inputs for unit tests. I wouldn't suggest
  8. # using it for anything else.
  9. import base64
  10. import binascii
  11. import ctypes
  12. import ctypes.util
  13. import hashlib
  14. crypt = ctypes.CDLL(ctypes.util.find_library('crypto'))
  15. BIO_s_mem = crypt.BIO_s_mem
  16. BIO_s_mem.argtypes = []
  17. BIO_s_mem.restype = ctypes.c_void_p
  18. BIO_new = crypt.BIO_new
  19. BIO_new.argtypes = [ctypes.c_void_p]
  20. BIO_new.restype = ctypes.c_void_p
  21. RSA_generate_key = crypt.RSA_generate_key
  22. RSA_generate_key.argtypes = [ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p]
  23. RSA_generate_key.restype = ctypes.c_void_p
  24. RSA_private_encrypt = crypt.RSA_private_encrypt
  25. RSA_private_encrypt.argtypes = [
  26. ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int ]
  27. RSA_private_encrypt.restype = ctypes.c_int
  28. i2d_RSAPublicKey = crypt.i2d_RSAPublicKey
  29. i2d_RSAPublicKey.argtypes = [
  30. ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p)
  31. ]
  32. i2d_RSAPublicKey.restype = ctypes.c_int
  33. def b64(x):
  34. x = base64.b64encode(x)
  35. res = []
  36. for i in xrange(0, len(x), 64):
  37. res.append(x[i:i+64]+"\n")
  38. return "".join(res)
  39. def bio_extract(bio):
  40. buf = ctypes.c_char_p()
  41. length = crypt.BIO_ctrl(bio, 3, 0, ctypes.byref(buf))
  42. return ctypes.string_at(buf, length)
  43. def make_key(e=65537):
  44. rsa = crypt.RSA_generate_key(1024, e, None, None)
  45. bio = BIO_new(BIO_s_mem())
  46. crypt.PEM_write_bio_RSAPublicKey(bio, rsa)
  47. pem = bio_extract(bio).rstrip()
  48. crypt.BIO_free(bio)
  49. buf = ctypes.create_string_buffer(1024)
  50. pBuf = ctypes.c_char_p(ctypes.addressof(buf))
  51. n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
  52. s = buf.raw[:n]
  53. digest = hashlib.sha1(s).digest()
  54. return (rsa,pem,digest)
  55. def signdesc(body, args_out=None):
  56. rsa, ident_pem, id_digest = make_key()
  57. _, onion_pem, _ = make_key()
  58. hexdigest = binascii.b2a_hex(id_digest).upper()
  59. fingerprint = " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
  60. MAGIC = "<<<<<<MAGIC>>>>>>"
  61. args = {
  62. "RSA-IDENTITY" : ident_pem,
  63. "ONION-KEY" : onion_pem,
  64. "FINGERPRINT" : fingerprint,
  65. "FINGERPRINT-NOSPACE" : hexdigest,
  66. "RSA-SIGNATURE" : MAGIC
  67. }
  68. if args_out:
  69. args_out.update(args)
  70. body = body.format(**args)
  71. idx = body.rindex("\nrouter-signature")
  72. end_of_sig = body.index("\n", idx+1)
  73. signed_part = body[:end_of_sig+1]
  74. digest = hashlib.sha1(signed_part).digest()
  75. assert len(digest) == 20
  76. buf = ctypes.create_string_buffer(1024)
  77. n = RSA_private_encrypt(20, digest, buf, rsa, 1)
  78. sig = buf.raw[:n]
  79. sig = """-----BEGIN SIGNATURE-----
  80. %s
  81. -----END SIGNATURE-----""" % b64(sig).rstrip()
  82. body = body.replace(MAGIC, sig)
  83. return body.rstrip()
  84. def emit_ri(name, body, args_out=None):
  85. print "const char %s[] ="%name
  86. body = "\n".join(line.rstrip() for line in body.split("\n"))+"\n"
  87. b = signdesc(body, args_out)
  88. for line in b.split("\n"):
  89. print ' "%s\\n"'%line
  90. print " ;"
  91. def emit_ei(name, body):
  92. args = { 'NAME' : name }
  93. emit_ri(name, body, args)
  94. args['key'] = "\n".join(
  95. ' "%s\\n"'%line for line in args['RSA-IDENTITY'].split("\n"))
  96. print """
  97. const char {NAME}_fp[] = "{FINGERPRINT-NOSPACE}";
  98. const char {NAME}_key[] =
  99. {key};""".format(**args)
  100. if 0:
  101. emit_ri("minimal",
  102. """\
  103. router fred 127.0.0.1 9001 0 9002
  104. signing-key
  105. {RSA-IDENTITY}
  106. onion-key
  107. {ONION-KEY}
  108. published 2014-10-05 12:00:00
  109. bandwidth 1000 1000 1000
  110. reject *:*
  111. router-signature
  112. {RSA-SIGNATURE}
  113. """)
  114. if 0:
  115. emit_ri("maximal",
  116. """\
  117. router fred 127.0.0.1 9001 0 9002
  118. signing-key
  119. {RSA-IDENTITY}
  120. onion-key
  121. {ONION-KEY}
  122. published 2014-10-05 12:00:00
  123. bandwidth 1000 1000 1000
  124. reject 127.0.0.1:*
  125. accept *:80
  126. reject *:*
  127. ipv6-policy accept 80,100,101
  128. ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw
  129. uptime 1000
  130. hibernating 0
  131. unrecognized-keywords are just dandy in this format
  132. platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
  133. contact O.W.Jones
  134. fingerprint {FINGERPRINT}
  135. read-history 900 1,2,3,4
  136. write-history 900 1,2,3,4
  137. extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  138. hidden-service-dir
  139. allow-single-hop-exits
  140. family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  141. caches-extra-info
  142. or-address [::1:2:3:4]:9999
  143. or-address 127.0.0.99:10000
  144. opt fred is a fine router
  145. router-signature
  146. {RSA-SIGNATURE}
  147. """)
  148. if 0:
  149. emit_ei("maximal",
  150. """\
  151. extra-info bob {FINGERPRINT-NOSPACE}
  152. published 2014-10-05 20:07:00
  153. opt foobarbaz
  154. read-history 900 1,2,3
  155. write-history 900 1,2,3
  156. dirreq-v2-ips 1
  157. dirreq-v3-ips 100
  158. dirreq-v3-reqs blahblah
  159. dirreq-v2-share blahblah
  160. dirreq-v3-share blahblah
  161. dirreq-v2-resp djfkdj
  162. dirreq-v3-resp djfkdj
  163. dirreq-v2-direct-dl djfkdj
  164. dirreq-v3-direct-dl djfkdj
  165. dirreq-v2-tunneled-dl djfkdj
  166. dirreq-v3-tunneled-dl djfkdj
  167. dirreq-stats-end foobar
  168. entry-ips jfsdfds
  169. entry-stats-end ksdflkjfdkf
  170. cell-stats-end FOO
  171. cell-processed-cells FOO
  172. cell-queued-cells FOO
  173. cell-time-in-queue FOO
  174. cell-circuits-per-decile FOO
  175. exit-stats-end FOO
  176. exit-kibibytes-written FOO
  177. exit-kibibytes-read FOO
  178. exit-streams-opened FOO
  179. router-signature
  180. {RSA-SIGNATURE}
  181. """)
  182. if 0:
  183. emit_ei("minimal",
  184. """\
  185. extra-info bob {FINGERPRINT-NOSPACE}
  186. published 2014-10-05 20:07:00
  187. router-signature
  188. {RSA-SIGNATURE}
  189. """)