1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2012 OpenStack LLC
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
23
from keystone import config
27
DIR_PERMS = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | \
28
stat.S_IRGRP | stat.S_IXGRP | \
29
stat.S_IROTH | stat.S_IXOTH
30
CERT_PERMS = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH
31
PRIV_PERMS = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
32
DEFAULT_SUBJECT = "/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com"
35
def file_exists(file_path):
36
sys.stdout.write("Looking for %s:\t" % file_path)
37
if os.path.exists(file_path):
45
def make_dirs(file_name):
46
dir = os.path.dirname(file_name)
47
if not file_exists(dir):
48
os.makedirs(dir, DIR_PERMS)
51
class ConfigurePKI(object):
52
"""Generate files for PKI siginging using OpenSSL
54
Signed tokens require a private key and signing certificate which itself
55
must be signed by a CA. This class generates them with workable defaults
56
if each of the files are not present
58
def __init__(self, *args, **kw):
59
self.conf_dir = os.path.dirname(CONF.signing.ca_certs)
60
self.ssl_config_file_name = os.path.join(self.conf_dir, "openssl.conf")
61
self.ca_key_file = os.path.join(self.conf_dir, "cakey.pem")
62
self.request_file_name = os.path.join(self.conf_dir, "req.pem")
63
self.ssl_dictionary = \
65
'conf_dir': self.conf_dir,
66
"ca_cert": CONF.signing.ca_certs,
67
"ssl_config": self.ssl_config_file_name,
68
"ca_private_key": self.ca_key_file,
69
"ca_cert_cn": "hostname",
70
"request_file": self.request_file_name,
71
"signing_key": CONF.signing.keyfile,
72
"signing_cert": CONF.signing.certfile,
73
"default_subject": DEFAULT_SUBJECT,
74
"key_size": int(CONF.signing.key_size),
75
"valid_days": int(CONF.signing.valid_days),
76
"ca_password": CONF.signing.ca_password
79
def exec_command(self, command):
80
to_exec = command % self.ssl_dictionary
82
subprocess.check_call(to_exec.rsplit(" "))
84
def build_ssl_config_file(self):
85
if not file_exists(self.ssl_config_file_name):
86
make_dirs(self.ssl_config_file_name)
87
ssl_config_file = open(self.ssl_config_file_name, 'w')
88
ssl_config_file.write(self.sslconfig % self.ssl_dictionary)
89
ssl_config_file.close()
90
os.chmod(self.ssl_config_file_name, CERT_PERMS)
92
index_file_name = os.path.join(self.conf_dir, "index.txt")
93
if not file_exists(index_file_name):
94
index_file = open(index_file_name, 'w')
97
os.chmod(self.ssl_config_file_name, PRIV_PERMS)
99
serial_file_name = os.path.join(self.conf_dir, "serial")
100
if not file_exists(serial_file_name):
101
index_file = open(serial_file_name, 'w')
102
index_file.write("01")
104
os.chmod(self.ssl_config_file_name, PRIV_PERMS)
106
def build_ca_cert(self):
107
if not file_exists(CONF.signing.ca_certs):
108
if not os.path.exists(self.ca_key_file):
109
make_dirs(self.ca_key_file)
110
self.exec_command("openssl genrsa -out %(ca_private_key)s "\
111
"%(key_size)d -config %(ssl_config)s")
112
os.chmod(self.ssl_dictionary["ca_private_key"], stat.S_IRUSR)
113
print("Generating CA certificate")
114
self.exec_command('openssl req -new -x509 -extensions v3_ca ' \
115
'-passin pass:%(ca_password)s ' \
116
'-key %(ca_private_key)s -out %(ca_cert)s '\
117
'-days %(valid_days)d ' \
118
'-config %(ssl_config)s ' \
119
'-subj %(default_subject)s')
120
os.chmod(self.ssl_dictionary["ca_cert"], CERT_PERMS)
122
def build_private_key(self):
123
if not file_exists(CONF.signing.keyfile):
124
make_dirs(CONF.signing.keyfile)
126
self.exec_command("openssl genrsa -out %(signing_key)s "\
128
"-config %(ssl_config)s")
129
os.chmod(os.path.dirname(self.ssl_dictionary["signing_key"]),
131
os.chmod(self.ssl_dictionary["signing_key"], stat.S_IRUSR)
133
def build_signing_cert(self):
134
if not file_exists(CONF.signing.certfile):
135
make_dirs(CONF.signing.certfile)
136
self.exec_command("openssl req -key %(signing_key)s -new -nodes "\
137
"-out %(request_file)s -config %(ssl_config)s "\
138
"-subj %(default_subject)s")
139
self.exec_command("openssl ca -batch -out %(signing_cert)s "\
140
"-config %(ssl_config)s "\
141
"-infiles %(request_file)s")
144
self.build_ssl_config_file()
146
self.build_private_key()
147
self.build_signing_cert()
150
# OpenSSL configuration file.
153
# Establish working directory.
157
default_ca = CA_default
162
database = $dir/index.txt
163
certificate = %(ca_cert)s
164
private_key = %(ca_private_key)s
171
policy = policy_match
174
stateOrProvinceName = match
175
organizationName = match
176
organizationalUnitName = optional
177
commonName = supplied
178
emailAddress = optional
181
default_bits = 1024 # Size of keys
182
default_keyfile = key.pem # name of generated keys
183
default_md = md5 # message digest algorithm
184
string_mask = nombstr # permitted characters
185
distinguished_name = req_distinguished_name
186
req_extensions = v3_req
188
[ req_distinguished_name ]
189
0.organizationName = Organization Name (company)
190
organizationalUnitName = Organizational Unit Name (department, division)
191
emailAddress = Email Address
192
emailAddress_max = 40
193
localityName = Locality Name (city, district)
194
stateOrProvinceName = State or Province Name (full name)
195
countryName = Country Name (2 letter code)
198
commonName = Common Name (hostname, IP, or your name)
200
# Default values for the above, for consistency and less typing.
201
0.organizationName_default = Openstack, Inc
202
localityName_default = Undefined
203
stateOrProvinceName_default = Undefined
204
countryName_default = US
205
commonName_default = %(ca_cert_cn)s
208
basicConstraints = CA:TRUE
209
subjectKeyIdentifier = hash
210
authorityKeyIdentifier = keyid:always,issuer:always
213
basicConstraints = CA:FALSE
214
subjectKeyIdentifier = hash"""