import repository from arizona
[raven.git] / 2.0 / c / keyconvert / keyconvert.py
1 # SSH to SSL Key Converter
2 # Description: Convert SSH public keys to OpenSSL public keys
3 # Author: Scott Baker
4 # Project: Raven, http://raven.cs.arizona.edu
5
6 import base64
7 import os
8 import socket
9 import sys
10 import tempfile
11
12 import asn1
13
14 def dec2hex(d):
15         hv = hex(d).replace('0x', '')
16         if (len(hv) == 1) or (len(hv) == 3):\r
17             hv = '0'+hv
18         return hv
19
20 def to_hex(s):
21     lst = []\r
22     for ch in s:\r
23         hv = hex(ord(ch)).replace('0x', '')\r
24         if len(hv) == 1:\r
25             hv = '0'+hv\r
26         lst.append(hv)\r
27 \r
28     return reduce(lambda x,y:x+y, lst)\r
29
30 def get_str(src):
31     len = (ord(src[3]) << 24) + (ord(src[2]) <<16) + (ord(src[1]) << 8) + ord(src[0])
32     len = socket.ntohl(len)
33
34     src = src[4:]
35     dest = src[:len]
36     src = src[len:]
37
38     return (src, dest)
39
40 # convert a string in DER format to PEM format
41
42 def pem_format(x):
43        x = base64.b64encode(x)
44        result = "-----BEGIN PUBLIC KEY-----\n"
45        while (x != ""):
46           result = result + x[:64] + "\n"
47           x = x[64:]
48        result = result + "-----END PUBLIC KEY-----\n"
49        return result
50
51 # an all-python solution, using ASN.1 python routines
52
53 def ssh_to_ssl(key_str):
54    tmp = base64.b64decode(key_str)
55    (tmp, kind) = get_str(tmp)
56
57    if (kind == "ssh-rsa"):
58        (tmp, e) = get_str(tmp)
59        (tmp, n) = get_str(tmp)
60
61        der = asn1.rsa_pubkey(n,e).encode()
62        ssl_key_str = pem_format(der)
63
64        f = open("foo.der","w")
65        f.write(der)
66        f.close()
67    else:
68        (tmp, p) = get_str(tmp)
69        (tmp, q) = get_str(tmp)
70        (tmp, g) = get_str(tmp)
71        (tmp, pk) = get_str(tmp)
72
73        der = asn1.dsa_pubkey(p,q,g,pk).encode()
74        ssl_key_str = pem_format(der)
75
76        f = open("foo.der","w")
77        f.write(der)
78        f.close()
79
80    return ssl_key_str
81
82 # a hybrid python/OpenSSL solution, letting openSSL do some of the work
83 # for us.
84
85 def ssh_to_ssl_old(key_str):
86    (conf_fd, conf_fn) = tempfile.mkstemp(prefix="keyconv", suffix="conf")
87    (der_fd, der_fn) = tempfile.mkstemp(prefix="keyconv", suffix="der")
88    (pem_fd, pem_fn) = tempfile.mkstemp(prefix="keyconv", suffix="pem")
89
90    os.close(conf_fd)
91    os.close(der_fd)
92    os.close(pem_fd)
93
94    try:
95        tmp = base64.b64decode(key_str)
96        (tmp, kind) = get_str(tmp)
97
98        if (kind == "ssh-rsa"):
99            (tmp, e) = get_str(tmp)
100            (tmp, n) = get_str(tmp)
101
102            f = file(conf_fn, "w")
103            f.write("asn1=SEQUENCE:pubkeyinfo\n\n")
104            f.write("[pubkeyinfo]\n")
105            f.write("algorithm=SEQUENCE:rsa_alg\n")
106            f.write("pubkey=BITWRAP,SEQUENCE:rsapubkey\n\n")
107            f.write("[rsa_alg]\n")
108            f.write("algorithm=OID:rsaEncryption\n")\r
109            f.write("parameter=NULL\n\n")\r
110            f.write("[rsapubkey]\n")\r
111            f.write("n=INTEGER:0x" + to_hex(n) + "\n")\r
112            f.write("e=INTEGER:0x" + to_hex(e) + "\n")\r
113            f.close()\r
114 \r
115            os.system("openssl asn1parse -genconf " + conf_fn + " -out " + der_fn)
116            os.system("openssl rsa -pubin -inform der -in " + der_fn + " -out " + pem_fn)
117
118            f = open(pem_fn,"r")
119            ssl_key_str = f.read()
120            f.close()
121        else:
122            (tmp, p) = get_str(tmp)
123            (tmp, q) = get_str(tmp)
124            (tmp, g) = get_str(tmp)
125            (tmp, pk) = get_str(tmp)
126
127            f = file(conf_fn, "w")
128            f.write("asn1=SEQUENCE:pubkeyinfo\n\n")
129            f.write("[pubkeyinfo]\n")
130            f.write("algorithm=SEQUENCE:dsa_alg\n")
131
132            # 02 means integer
133            # next byte is length.
134            #   if hi bit is unset then it's a short length (less than 128)
135            #   if hi bit is set then it's a long length
136            #            first byte is 0x80 + number of length bytes
137            #            remaining n bytes are length bytes
138
139            if len(pk)>=256:
140               f.write("pubkey=FORMAT:HEX,BITSTRING:" + "0282" + dec2hex(len(pk)) + to_hex(pk) + "\n\n")
141            elif len(pk)>=128:
142               f.write("pubkey=FORMAT:HEX,BITSTRING:" + "0281" + dec2hex(len(pk)) + to_hex(pk) + "\n\n")
143            else:
144               f.write("pubkey=FORMAT:HEX,BITSTRING:" + "02" + dec2hex(len(pk)) + to_hex(pk) + "\n\n")
145
146            f.write("[dsa_alg]\n")
147            f.write("algorithm=OID:dsaEncryption\n")\r
148            f.write("params=SEQUENCE:dssparam\n")\r
149            f.write("[dssparam]\n")\r
150            f.write("p=INTEGER:0x" + to_hex(p) + "\n")\r
151            f.write("q=INTEGER:0x" + to_hex(q) + "\n")\r
152            f.write("g=INTEGER:0x" + to_hex(g) + "\n")\r
153            f.close()\r
154 \r
155            os.system("openssl asn1parse -genconf " + conf_fn + " -out " + der_fn)
156            os.system("openssl dsa -pubin -inform der -in " + der_fn + " -out " + pem_fn)
157
158            f = open(pem_fn,"r")
159            ssl_key_str = f.read()
160            f.close()
161    finally:
162        if os.path.exists(conf_fn):
163            os.remove(conf_fn)
164        if os.path.exists(der_fn):
165            os.remove(der_fn)
166        if os.path.exists(pem_fn):
167            os.remove(pem_fn)
168        pass
169
170    return ssl_key_str
171
172 def main():
173    if (len(sys.argv) != 3):
174        print >> sys.stderr,  "syntax: keyconvert <infile> <outfile>"
175        sys.exit(1)
176
177    f = open(sys.argv[1])
178    line = f.read()
179    f.close()
180
181    parts = line.split(" ")
182    ssh_key_str = parts[1]
183
184    ssl_key_str = ssh_to_ssl(ssh_key_str)
185
186    f = open(sys.argv[2], "w")
187    f.write(ssl_key_str)
188    f.close()
189
190 if __name__ == "__main__":
191    main()
192
193
194