19 |
19 |
import tempfile
|
20 |
20 |
import os
|
21 |
21 |
import subprocess
|
22 |
|
import stat
|
23 |
22 |
import six
|
24 |
23 |
|
25 |
24 |
_openssl = 'openssl'
|
... | ... | |
54 |
53 |
return 1, None
|
55 |
54 |
|
56 |
55 |
|
57 |
|
def _protect_file(fd, filepath):
|
58 |
|
'''Make a file targeted by a file descriptor readable only by the current user
|
59 |
|
|
60 |
|
It's needed to be sure nobody can read the private key file we manage.
|
61 |
|
'''
|
62 |
|
os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
|
63 |
|
|
64 |
|
|
65 |
56 |
def check_key_pair_consistency(publickey=None, privatekey=None):
|
66 |
57 |
'''Check if two PEM key pair whether they are publickey or certificate, are
|
67 |
58 |
well formed and related.
|
68 |
59 |
'''
|
69 |
|
if publickey and privatekey:
|
70 |
|
try:
|
71 |
|
privatekey_file_fd, privatekey_fn = tempfile.mkstemp()
|
72 |
|
publickey_file_fd, publickey_fn = tempfile.mkstemp()
|
73 |
|
_protect_file(privatekey_file_fd, privatekey_fn)
|
74 |
|
_protect_file(publickey_file_fd, publickey_fn)
|
75 |
|
os.fdopen(privatekey_file_fd, 'w').write(privatekey)
|
76 |
|
os.fdopen(publickey_file_fd, 'w').write(publickey)
|
77 |
|
if 'BEGIN CERTIFICATE' in publickey:
|
78 |
|
rc1, modulus1 = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-modulus'])
|
79 |
|
else:
|
80 |
|
rc1, modulus1 = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
|
81 |
|
if rc1 != 0:
|
82 |
|
rc1, modulus1 = _call_openssl(['dsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
|
|
60 |
if not publickey or not privatekey:
|
|
61 |
return None
|
|
62 |
|
|
63 |
privatekey_file = tempfile.NamedTemporaryFile(mode='w')
|
|
64 |
publickey_file = tempfile.NamedTemporaryFile(mode='w')
|
|
65 |
with privatekey_file, publickey_file:
|
|
66 |
|
|
67 |
privatekey_file.write(privatekey)
|
|
68 |
privatekey_file.flush()
|
|
69 |
publickey_file.write(publickey)
|
|
70 |
publickey_file.flush()
|
83 |
71 |
|
|
72 |
if 'BEGIN CERTIFICATE' in publickey:
|
|
73 |
rc1, modulus1 = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-modulus'])
|
|
74 |
else:
|
|
75 |
rc1, modulus1 = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
|
84 |
76 |
if rc1 != 0:
|
85 |
|
return False
|
|
77 |
rc1, modulus1 = _call_openssl(['dsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
|
86 |
78 |
|
87 |
|
rc2, modulus2 = _call_openssl(['rsa', '-in', privatekey_fn, '-noout', '-modulus'])
|
88 |
|
if rc2 != 0:
|
89 |
|
rc2, modulus2 = _call_openssl(['dsa', '-in', privatekey_fn, '-noout', '-modulus'])
|
|
79 |
if rc1 != 0:
|
|
80 |
return False
|
90 |
81 |
|
91 |
|
if rc1 == 0 and rc2 == 0 and modulus1 == modulus2:
|
92 |
|
return True
|
93 |
|
else:
|
94 |
|
return False
|
95 |
|
finally:
|
96 |
|
os.unlink(privatekey_fn)
|
97 |
|
os.unlink(publickey_fn)
|
98 |
|
return None
|
|
82 |
rc2, modulus2 = _call_openssl(['rsa', '-in', privatekey_file.name, '-noout', '-modulus'])
|
|
83 |
if rc2 != 0:
|
|
84 |
rc2, modulus2 = _call_openssl(['dsa', '-in', privatekey_file.name, '-noout', '-modulus'])
|
|
85 |
|
|
86 |
if rc1 == 0 and rc2 == 0 and modulus1 == modulus2:
|
|
87 |
return True
|
|
88 |
else:
|
|
89 |
return False
|
99 |
90 |
|
100 |
91 |
|
101 |
92 |
def generate_rsa_keypair(numbits=1024):
|
102 |
93 |
'''Generate simple RSA public and private key files
|
103 |
94 |
'''
|
104 |
|
try:
|
105 |
|
privatekey_file_fd, privatekey_fn = tempfile.mkstemp()
|
106 |
|
publickey_file_fd, publickey_fn = tempfile.mkstemp()
|
107 |
|
_protect_file(privatekey_file_fd, privatekey_fn)
|
108 |
|
_protect_file(publickey_file_fd, publickey_fn)
|
109 |
|
rc1, _ = _call_openssl(['genrsa', '-out', privatekey_fn, '-passout', 'pass:', str(numbits)])
|
110 |
|
rc2, _ = _call_openssl(['rsa', '-in', privatekey_fn, '-pubout', '-out', publickey_fn])
|
111 |
|
if rc1 != 0 or rc2 != 0:
|
|
95 |
privatekey_file = tempfile.NamedTemporaryFile(mode='r')
|
|
96 |
publickey_file = tempfile.NamedTemporaryFile(mode='r')
|
|
97 |
|
|
98 |
with privatekey_file, publickey_file:
|
|
99 |
rc1, _ = _call_openssl(['genrsa', '-out', privatekey_file.name, '-passout', 'pass:', str(numbits)])
|
|
100 |
if rc1 != 0:
|
|
101 |
raise Exception('Failed to generate a key')
|
|
102 |
rc2, _ = _call_openssl(['rsa', '-in', privatekey_file.name, '-pubout', '-out', publickey_file.name])
|
|
103 |
if rc2 != 0:
|
112 |
104 |
raise Exception('Failed to generate a key')
|
113 |
|
return (os.fdopen(publickey_file_fd).read(), os.fdopen(privatekey_file_fd).read())
|
114 |
|
finally:
|
115 |
|
os.unlink(privatekey_fn)
|
116 |
|
os.unlink(publickey_fn)
|
|
105 |
return (publickey_file.read(), privatekey_file.read())
|
117 |
106 |
|
118 |
107 |
|
119 |
108 |
def get_rsa_public_key_modulus(publickey):
|
120 |
|
try:
|
121 |
|
publickey_file_fd, publickey_fn = tempfile.mkstemp()
|
122 |
|
os.fdopen(publickey_file_fd, 'w').write(publickey)
|
|
109 |
publickey_file = tempfile.NamedTemporaryFile(mode='w')
|
|
110 |
|
|
111 |
with publickey_file:
|
|
112 |
publickey_file.write(publickey)
|
|
113 |
publickey_file.flush()
|
|
114 |
|
123 |
115 |
if 'BEGIN PUBLIC' in publickey:
|
124 |
|
rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
|
|
116 |
rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
|
125 |
117 |
elif 'BEGIN RSA PRIVATE KEY' in publickey:
|
126 |
|
rc, modulus = _call_openssl(['rsa', '-in', publickey_fn, '-noout', '-modulus'])
|
|
118 |
rc, modulus = _call_openssl(['rsa', '-in', publickey_file.name, '-noout', '-modulus'])
|
127 |
119 |
elif 'BEGIN CERTIFICATE' in publickey:
|
128 |
|
rc, modulus = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-modulus'])
|
|
120 |
rc, modulus = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-modulus'])
|
129 |
121 |
else:
|
130 |
122 |
return None
|
|
123 |
|
131 |
124 |
i = modulus.find('=')
|
|
125 |
|
132 |
126 |
if rc == 0 and i:
|
133 |
127 |
return int(modulus[i + 1:].strip(), 16)
|
134 |
|
finally:
|
135 |
|
os.unlink(publickey_fn)
|
136 |
128 |
return None
|
137 |
129 |
|
138 |
130 |
|
139 |
131 |
def get_rsa_public_key_exponent(publickey):
|
140 |
|
try:
|
141 |
|
publickey_file_fd, publickey_fn = tempfile.mkstemp()
|
142 |
|
os.fdopen(publickey_file_fd, 'w').write(publickey)
|
|
132 |
publickey_file = tempfile.NamedTemporaryFile(mode='w')
|
|
133 |
|
|
134 |
with publickey_file:
|
|
135 |
publickey_file.write(publickey)
|
|
136 |
publickey_file.flush()
|
|
137 |
|
143 |
138 |
_exponent = 'Exponent: '
|
144 |
139 |
if 'BEGIN PUBLIC' in publickey:
|
145 |
|
rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-text'])
|
|
140 |
rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-text'])
|
146 |
141 |
elif 'BEGIN RSA PRIVATE' in publickey:
|
147 |
|
rc, modulus = _call_openssl(['rsa', '-in', publickey_fn, '-noout', '-text'])
|
|
142 |
rc, modulus = _call_openssl(['rsa', '-in', publickey_file.name, '-noout', '-text'])
|
148 |
143 |
_exponent = 'publicExponent: '
|
149 |
144 |
elif 'BEGIN CERTIFICATE' in publickey:
|
150 |
|
rc, modulus = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-text'])
|
|
145 |
rc, modulus = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-text'])
|
151 |
146 |
else:
|
152 |
147 |
return None
|
153 |
148 |
i = modulus.find(_exponent)
|
154 |
149 |
j = modulus.find('(', i)
|
155 |
150 |
if rc == 0 and i and j:
|
156 |
151 |
return int(modulus[i + len(_exponent):j].strip())
|
157 |
|
finally:
|
158 |
|
os.unlink(publickey_fn)
|
159 |
152 |
return None
|
160 |
153 |
|
161 |
154 |
|
... | ... | |
178 |
171 |
|
179 |
172 |
mod = get_rsa_public_key_modulus(publickey)
|
180 |
173 |
exp = get_rsa_public_key_exponent(publickey)
|
|
174 |
mod_byte_length = (mod.bit_length() + 7) // 8
|
|
175 |
exp_byte_length = (exp.bit_length() + 7) // 8
|
|
176 |
mod_bytes = mod.to_bytes(mod_byte_length, byteorder='big')
|
|
177 |
exp_bytes = exp.to_bytes(exp_byte_length, byteorder='big')
|
|
178 |
mod_cryptobinary = base64.b64encode(mod_bytes).decode('ascii')
|
|
179 |
exp_cryptobinary = base64.b64encode(exp_bytes).decode('ascii')
|
181 |
180 |
return (
|
182 |
181 |
'<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">\n\t'
|
183 |
182 |
'<Modulus>%s</Modulus>\n\t'
|
184 |
183 |
'<Exponent>%s</Exponent>\n</RSAKeyValue>' % (
|
185 |
|
base64.b64encode(int_to_bin(mod)), base64.b64encode(int_to_bin(exp))))
|
|
184 |
mod_cryptobinary,
|
|
185 |
exp_cryptobinary)
|
|
186 |
)
|