~gandelman-a/ubuntu/precise/keystone/UCA_2012.2.1

« back to all changes in this revision

Viewing changes to keystone/common/openssl.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-07-06 10:37:01 UTC
  • mfrom: (1.1.20)
  • Revision ID: package-import@ubuntu.com-20120706103701-rswdykm7fqypbavg
Tags: 2012.2~f2-0ubuntu1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2012 OpenStack LLC
 
4
#
 
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
 
8
#
 
9
#      http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
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
 
15
#
 
16
 
 
17
import os
 
18
import stat
 
19
import subprocess
 
20
import sys
 
21
import stat
 
22
 
 
23
from keystone import config
 
24
 
 
25
 
 
26
CONF = config.CONF
 
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"
 
33
 
 
34
 
 
35
def file_exists(file_path):
 
36
    sys.stdout.write("Looking for %s:\t" % file_path)
 
37
    if os.path.exists(file_path):
 
38
        print("[FOUND]")
 
39
        return True
 
40
    else:
 
41
        print("[NOT FOUND]")
 
42
        return False
 
43
 
 
44
 
 
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)
 
49
 
 
50
 
 
51
class ConfigurePKI(object):
 
52
    """Generate files for PKI siginging using OpenSSL
 
53
 
 
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
 
57
    """
 
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 = \
 
64
            {
 
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
 
77
             }
 
78
 
 
79
    def exec_command(self, command):
 
80
        to_exec = command % self.ssl_dictionary
 
81
        print (to_exec)
 
82
        subprocess.check_call(to_exec.rsplit(" "))
 
83
 
 
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)
 
91
 
 
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')
 
95
            index_file.write("")
 
96
            index_file.close()
 
97
        os.chmod(self.ssl_config_file_name, PRIV_PERMS)
 
98
 
 
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")
 
103
            index_file.close()
 
104
        os.chmod(self.ssl_config_file_name, PRIV_PERMS)
 
105
 
 
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)
 
121
 
 
122
    def build_private_key(self):
 
123
        if not file_exists(CONF.signing.keyfile):
 
124
            make_dirs(CONF.signing.keyfile)
 
125
 
 
126
            self.exec_command("openssl genrsa -out %(signing_key)s "\
 
127
                              "%(key_size)d "\
 
128
                              "-config %(ssl_config)s")
 
129
        os.chmod(os.path.dirname(self.ssl_dictionary["signing_key"]),
 
130
                 PRIV_PERMS)
 
131
        os.chmod(self.ssl_dictionary["signing_key"], stat.S_IRUSR)
 
132
 
 
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")
 
142
 
 
143
    def run(self):
 
144
        self.build_ssl_config_file()
 
145
        self.build_ca_cert()
 
146
        self.build_private_key()
 
147
        self.build_signing_cert()
 
148
 
 
149
    sslconfig = """
 
150
# OpenSSL configuration file.
 
151
#
 
152
 
 
153
# Establish working directory.
 
154
 
 
155
dir            = %(conf_dir)s
 
156
[ ca ]
 
157
default_ca        = CA_default
 
158
 
 
159
[ CA_default ]
 
160
new_certs_dir     = $dir
 
161
serial            = $dir/serial
 
162
database          = $dir/index.txt
 
163
certificate       = %(ca_cert)s
 
164
private_key       = %(ca_private_key)s
 
165
default_days      = 365
 
166
default_md        = md5
 
167
preserve          = no
 
168
email_in_dn       = no
 
169
nameopt           = default_ca
 
170
certopt           = default_ca
 
171
policy            = policy_match
 
172
[ policy_match ]
 
173
countryName             = match
 
174
stateOrProvinceName     = match
 
175
organizationName        = match
 
176
organizationalUnitName  = optional
 
177
commonName              = supplied
 
178
emailAddress            = optional
 
179
 
 
180
[ req ]
 
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
 
187
 
 
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)
 
196
countryName_min        = 2
 
197
countryName_max        = 2
 
198
commonName        = Common Name (hostname, IP, or your name)
 
199
commonName_max        = 64
 
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
 
206
 
 
207
[ v3_ca ]
 
208
basicConstraints = CA:TRUE
 
209
subjectKeyIdentifier = hash
 
210
authorityKeyIdentifier = keyid:always,issuer:always
 
211
 
 
212
[ v3_req ]
 
213
basicConstraints = CA:FALSE
 
214
subjectKeyIdentifier = hash"""