123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #!/usr/bin/python
- # Copyright 2014, The Tor Project, Inc.
- # See LICENSE for license information
- # This is a kludgey python script that uses ctypes and openssl to sign
- # router descriptors and extrainfo documents and put all the keys in
- # the right places. There are examples at the end of the file.
- # I've used this to make inputs for unit tests. I wouldn't suggest
- # using it for anything else.
- import base64
- import binascii
- import ctypes
- import ctypes.util
- import hashlib
- crypt = ctypes.CDLL(ctypes.util.find_library('crypto'))
- BIO_s_mem = crypt.BIO_s_mem
- BIO_s_mem.argtypes = []
- BIO_s_mem.restype = ctypes.c_void_p
- BIO_new = crypt.BIO_new
- BIO_new.argtypes = [ctypes.c_void_p]
- BIO_new.restype = ctypes.c_void_p
- RSA_generate_key = crypt.RSA_generate_key
- RSA_generate_key.argtypes = [ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p]
- RSA_generate_key.restype = ctypes.c_void_p
- RSA_private_encrypt = crypt.RSA_private_encrypt
- RSA_private_encrypt.argtypes = [
- ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int ]
- RSA_private_encrypt.restype = ctypes.c_int
- i2d_RSAPublicKey = crypt.i2d_RSAPublicKey
- i2d_RSAPublicKey.argtypes = [
- ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p)
- ]
- i2d_RSAPublicKey.restype = ctypes.c_int
- def b64(x):
- x = base64.b64encode(x)
- res = []
- for i in xrange(0, len(x), 64):
- res.append(x[i:i+64]+"\n")
- return "".join(res)
- def bio_extract(bio):
- buf = ctypes.c_char_p()
- length = crypt.BIO_ctrl(bio, 3, 0, ctypes.byref(buf))
- return ctypes.string_at(buf, length)
- def make_key(e=65537):
- rsa = crypt.RSA_generate_key(1024, e, None, None)
- bio = BIO_new(BIO_s_mem())
- crypt.PEM_write_bio_RSAPublicKey(bio, rsa)
- pem = bio_extract(bio).rstrip()
- crypt.BIO_free(bio)
- buf = ctypes.create_string_buffer(1024)
- pBuf = ctypes.c_char_p(ctypes.addressof(buf))
- n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
- s = buf.raw[:n]
- digest = hashlib.sha1(s).digest()
- return (rsa,pem,digest)
- def signdesc(body, args_out=None):
- rsa, ident_pem, id_digest = make_key()
- _, onion_pem, _ = make_key()
- hexdigest = binascii.b2a_hex(id_digest).upper()
- fingerprint = " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
- MAGIC = "<<<<<<MAGIC>>>>>>"
- args = {
- "RSA-IDENTITY" : ident_pem,
- "ONION-KEY" : onion_pem,
- "FINGERPRINT" : fingerprint,
- "FINGERPRINT-NOSPACE" : hexdigest,
- "RSA-SIGNATURE" : MAGIC
- }
- if args_out:
- args_out.update(args)
- body = body.format(**args)
- idx = body.rindex("\nrouter-signature")
- end_of_sig = body.index("\n", idx+1)
- signed_part = body[:end_of_sig+1]
- digest = hashlib.sha1(signed_part).digest()
- assert len(digest) == 20
- buf = ctypes.create_string_buffer(1024)
- n = RSA_private_encrypt(20, digest, buf, rsa, 1)
- sig = buf.raw[:n]
- sig = """-----BEGIN SIGNATURE-----
- %s
- -----END SIGNATURE-----""" % b64(sig).rstrip()
- body = body.replace(MAGIC, sig)
- return body.rstrip()
- def emit_ri(name, body, args_out=None):
- print "const char %s[] ="%name
- body = "\n".join(line.rstrip() for line in body.split("\n"))+"\n"
- b = signdesc(body, args_out)
- for line in b.split("\n"):
- print ' "%s\\n"'%line
- print " ;"
- def emit_ei(name, body):
- args = { 'NAME' : name }
- emit_ri(name, body, args)
- args['key'] = "\n".join(
- ' "%s\\n"'%line for line in args['RSA-IDENTITY'].split("\n"))
- print """
- const char {NAME}_fp[] = "{FINGERPRINT-NOSPACE}";
- const char {NAME}_key[] =
- {key};""".format(**args)
- if 0:
- emit_ri("minimal",
- """\
- router fred 127.0.0.1 9001 0 9002
- signing-key
- {RSA-IDENTITY}
- onion-key
- {ONION-KEY}
- published 2014-10-05 12:00:00
- bandwidth 1000 1000 1000
- reject *:*
- router-signature
- {RSA-SIGNATURE}
- """)
- if 0:
- emit_ri("maximal",
- """\
- router fred 127.0.0.1 9001 0 9002
- signing-key
- {RSA-IDENTITY}
- onion-key
- {ONION-KEY}
- published 2014-10-05 12:00:00
- bandwidth 1000 1000 1000
- reject 127.0.0.1:*
- accept *:80
- reject *:*
- ipv6-policy accept 80,100,101
- ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw
- uptime 1000
- hibernating 0
- unrecognized-keywords are just dandy in this format
- platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
- contact O.W.Jones
- fingerprint {FINGERPRINT}
- read-history 900 1,2,3,4
- write-history 900 1,2,3,4
- extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- hidden-service-dir
- allow-single-hop-exits
- family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
- caches-extra-info
- or-address [::1:2:3:4]:9999
- or-address 127.0.0.99:10000
- opt fred is a fine router
- router-signature
- {RSA-SIGNATURE}
- """)
- if 0:
- emit_ei("maximal",
- """\
- extra-info bob {FINGERPRINT-NOSPACE}
- published 2014-10-05 20:07:00
- opt foobarbaz
- read-history 900 1,2,3
- write-history 900 1,2,3
- dirreq-v2-ips 1
- dirreq-v3-ips 100
- dirreq-v3-reqs blahblah
- dirreq-v2-share blahblah
- dirreq-v3-share blahblah
- dirreq-v2-resp djfkdj
- dirreq-v3-resp djfkdj
- dirreq-v2-direct-dl djfkdj
- dirreq-v3-direct-dl djfkdj
- dirreq-v2-tunneled-dl djfkdj
- dirreq-v3-tunneled-dl djfkdj
- dirreq-stats-end foobar
- entry-ips jfsdfds
- entry-stats-end ksdflkjfdkf
- cell-stats-end FOO
- cell-processed-cells FOO
- cell-queued-cells FOO
- cell-time-in-queue FOO
- cell-circuits-per-decile FOO
- exit-stats-end FOO
- exit-kibibytes-written FOO
- exit-kibibytes-read FOO
- exit-streams-opened FOO
- router-signature
- {RSA-SIGNATURE}
- """)
- if 0:
- emit_ei("minimal",
- """\
- extra-info bob {FINGERPRINT-NOSPACE}
- published 2014-10-05 20:07:00
- router-signature
- {RSA-SIGNATURE}
- """)
|