37
from nova import exception
36
gettext.install('nova', unicode=1)
38
from nova import context
38
40
from nova import flags
41
from nova import log as logging
44
LOG = logging.getLogger("nova.crypto")
41
45
FLAGS = flags.FLAGS
42
flags.DEFINE_string('ca_file', 'cacert.pem', 'Filename of root CA')
46
flags.DEFINE_string('ca_file', 'cacert.pem', _('Filename of root CA'))
47
flags.DEFINE_string('key_file',
48
os.path.join('private', 'cakey.pem'),
49
_('Filename of private key'))
50
flags.DEFINE_string('crl_file', 'crl.pem',
51
_('Filename of root Certificate Revokation List'))
43
52
flags.DEFINE_string('keys_path', '$state_path/keys',
44
'Where we keep our keys')
53
_('Where we keep our keys'))
45
54
flags.DEFINE_string('ca_path', '$state_path/CA',
46
'Where we keep our root CA')
47
flags.DEFINE_boolean('use_intermediate_ca', False,
48
'Should we use intermediate CAs for each project?')
51
def ca_path(project_id):
53
return "%s/INTER/%s/cacert.pem" % (FLAGS.ca_path, project_id)
54
return "%s/cacert.pem" % (FLAGS.ca_path)
55
_('Where we keep our root CA'))
56
flags.DEFINE_boolean('use_project_ca', False,
57
_('Should we use a CA for each project?'))
58
flags.DEFINE_string('user_cert_subject',
59
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
60
'OU=NovaDev/CN=%s-%s-%s',
61
_('Subject for certificate for users, '
62
'%s for project, user, timestamp'))
63
flags.DEFINE_string('project_cert_subject',
64
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
65
'OU=NovaDev/CN=project-ca-%s-%s',
66
_('Subject for certificate for projects, '
67
'%s for project, timestamp'))
68
flags.DEFINE_string('vpn_cert_subject',
69
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
70
'OU=NovaDev/CN=project-vpn-%s-%s',
71
_('Subject for certificate for vpns, '
72
'%s for project, timestamp'))
75
def ca_folder(project_id=None):
76
if FLAGS.use_project_ca and project_id:
77
return os.path.join(FLAGS.ca_path, 'projects', project_id)
81
def ca_path(project_id=None):
82
return os.path.join(ca_folder(project_id), FLAGS.ca_file)
85
def key_path(project_id=None):
86
return os.path.join(ca_folder(project_id), FLAGS.key_file)
57
89
def fetch_ca(project_id=None, chain=True):
58
if not FLAGS.use_intermediate_ca:
90
if not FLAGS.use_project_ca:
106
138
return '%s %s %s@%s\n' % (key_type, b64_blob, name, suffix)
109
def generate_x509_cert(subject, bits=1024):
141
def revoke_cert(project_id, file_name):
142
"""Revoke a cert by file name"""
144
os.chdir(ca_folder(project_id))
145
# NOTE(vish): potential race condition here
146
utils.execute("openssl ca -config ./openssl.cnf -revoke '%s'" % file_name)
147
utils.execute("openssl ca -gencrl -config ./openssl.cnf -out '%s'" %
152
def revoke_certs_by_user(user_id):
153
"""Revoke all user certs"""
154
admin = context.get_admin_context()
155
for cert in db.certificate_get_all_by_user(admin, user_id):
156
revoke_cert(cert['project_id'], cert['file_name'])
159
def revoke_certs_by_project(project_id):
160
"""Revoke all project certs"""
161
# NOTE(vish): This is somewhat useless because we can just shut down
163
admin = context.get_admin_context()
164
for cert in db.certificate_get_all_by_project(admin, project_id):
165
revoke_cert(cert['project_id'], cert['file_name'])
168
def revoke_certs_by_user_and_project(user_id, project_id):
169
"""Revoke certs for user in project"""
170
admin = context.get_admin_context()
171
for cert in db.certificate_get_all_by_user(admin, user_id, project_id):
172
revoke_cert(cert['project_id'], cert['file_name'])
175
def _project_cert_subject(project_id):
176
"""Helper to generate user cert subject"""
177
return FLAGS.project_cert_subject % (project_id, utils.isotime())
180
def _vpn_cert_subject(project_id):
181
"""Helper to generate user cert subject"""
182
return FLAGS.vpn_cert_subject % (project_id, utils.isotime())
185
def _user_cert_subject(user_id, project_id):
186
"""Helper to generate user cert subject"""
187
return FLAGS.user_cert_subject % (project_id, user_id, utils.isotime())
190
def generate_x509_cert(user_id, project_id, bits=1024):
191
"""Generate and sign a cert for user in project"""
192
subject = _user_cert_subject(user_id, project_id)
110
193
tmpdir = tempfile.mkdtemp()
111
194
keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
112
195
csrfile = os.path.join(tmpdir, 'temp.csr')
113
logging.debug("openssl genrsa -out %s %s" % (keyfile, bits))
114
utils.runthis("Generating private key: %s",
115
"openssl genrsa -out %s %s" % (keyfile, bits))
116
utils.runthis("Generating CSR: %s",
117
"openssl req -new -key %s -out %s -batch -subj %s" %
196
utils.execute("openssl genrsa -out %s %s" % (keyfile, bits))
197
utils.execute("openssl req -new -key %s -out %s -batch -subj %s" %
118
198
(keyfile, csrfile, subject))
119
199
private_key = open(keyfile).read()
120
200
csr = open(csrfile).read()
121
201
shutil.rmtree(tmpdir)
122
return (private_key, csr)
125
def sign_csr(csr_text, intermediate=None):
126
if not FLAGS.use_intermediate_ca:
129
return _sign_csr(csr_text, FLAGS.ca_path)
130
user_ca = "%s/INTER/%s" % (FLAGS.ca_path, intermediate)
131
if not os.path.exists(user_ca):
202
(serial, signed_csr) = sign_csr(csr, project_id)
203
fname = os.path.join(ca_folder(project_id), "newcerts/%s.pem" % serial)
204
cert = {'user_id': user_id,
205
'project_id': project_id,
207
db.certificate_create(context.get_admin_context(), cert)
208
return (private_key, signed_csr)
211
def _ensure_project_folder(project_id):
212
if not os.path.exists(ca_path(project_id)):
132
213
start = os.getcwd()
133
os.chdir(FLAGS.ca_path)
134
utils.runthis("Generating intermediate CA: %s",
135
"sh geninter.sh %s" % (intermediate))
214
os.chdir(ca_folder())
215
utils.execute("sh geninter.sh %s %s" %
216
(project_id, _project_cert_subject(project_id)))
137
return _sign_csr(csr_text, user_ca)
220
def generate_vpn_files(project_id):
221
project_folder = ca_folder(project_id)
222
csr_fn = os.path.join(project_folder, "server.csr")
223
crt_fn = os.path.join(project_folder, "server.crt")
225
if os.path.exists(crt_fn):
227
_ensure_project_folder(project_id)
229
os.chdir(ca_folder())
230
# TODO(vish): the shell scripts could all be done in python
231
utils.execute("sh genvpn.sh %s %s" %
232
(project_id, _vpn_cert_subject(project_id)))
233
with open(csr_fn, "r") as csrfile:
234
csr_text = csrfile.read()
235
(serial, signed_csr) = sign_csr(csr_text, project_id)
236
with open(crt_fn, "w") as crtfile:
237
crtfile.write(signed_csr)
241
def sign_csr(csr_text, project_id=None):
242
if not FLAGS.use_project_ca:
245
return _sign_csr(csr_text, ca_folder())
246
_ensure_project_folder(project_id)
247
project_folder = ca_folder(project_id)
248
return _sign_csr(csr_text, ca_folder(project_id))
140
251
def _sign_csr(csr_text, ca_folder):
141
252
tmpfolder = tempfile.mkdtemp()
142
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")
253
inbound = os.path.join(tmpfolder, "inbound.csr")
254
outbound = os.path.join(tmpfolder, "outbound.csr")
255
csrfile = open(inbound, "w")
143
256
csrfile.write(csr_text)
145
logging.debug("Flags path: %s" % ca_folder)
258
LOG.debug(_("Flags path: %s"), ca_folder)
146
259
start = os.getcwd()
147
260
# Change working dir to CA
148
261
os.chdir(ca_folder)
149
utils.runthis("Signing cert: %s",
150
"openssl ca -batch -out %s/outbound.crt "
151
"-config ./openssl.cnf -infiles %s/inbound.csr" %
152
(tmpfolder, tmpfolder))
262
utils.execute("openssl ca -batch -out %s -config "
263
"./openssl.cnf -infiles %s" % (outbound, inbound))
264
out, _err = utils.execute("openssl x509 -in %s -serial -noout" % outbound)
265
serial = out.rpartition("=")[2]
154
with open("%s/outbound.crt" % (tmpfolder), "r") as crtfile:
155
return crtfile.read()
267
with open(outbound, "r") as crtfile:
268
return (serial, crtfile.read())
158
271
def mkreq(bits, subject="foo", ca=0):