/usr/sbin/ca-make.py is in pyca 20031119-0.1ubuntu1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | #!/usr/bin/python
"""
ca-make.py - boot-strap of certificate authorities
(c) by Michael Stroeder, michael@stroeder.com
This script creates if non-existent (in the order given below,
does not overwrite existing files with file length > 0):
Directory structure:
dir Where everything is kept
certs Where the issued certs are kept
new_certs_dir default place for new certs.
crl_dir Where the issued crl are kept
Files:
database database index file.
serial The current serial number
Certificate files:
private_key The private key of the CA
certificate The CA certificate
"""
__version__ = '0.6.6'
import sys, string, os, stat, pwd, grp, getopt, time
def filenotvalid(pathname):
return not os.path.isfile(pathname) or os.stat(pathname)[stat.ST_SIZE]==0
def CheckedMakeDir(dirname,perms=0,uid=0,gid=0):
if not dirname:
return
if os.path.exists(dirname):
# Directory does already exist
if not os.path.isdir(dirname):
sys.stderr.write('Warning: %s already exists but is no directory.\n' % (dirname))
else:
# Create directory
try:
os.makedirs(dirname)
sys.stdout.write('Created directory %s\n' % (dirname))
except OSError:
sys.stderr.write('Error: Could not create directory %s.\n' % (dirname))
return
# Get current file stat info
fstat = os.stat(dirname)
if perms:
os.chmod(dirname,perms)
sys.stdout.write('Changed permissions of %s to %o\n' % (dirname,perms))
if (uid and fstat[stat.ST_UID]!=uid) or \
(gid and fstat[stat.ST_GID]!=gid):
if not uid:
uid=fstat[stat.ST_UID]
if not gid:
gid=pwd.getpwuid(uid)[3]
os.chown(dirname,uid,gid)
sys.stdout.write('Changed owner/group of %s to %s.%s\n' % (dirname,pwd.getpwuid(uid)[0],grp.getgrgid(gid)[0]))
def findoption(options,paramname):
for i in options:
if i[0]==paramname:
return i
return ()
def PrintUsage(ErrorMsg='',ErrorCode=1):
script_name = string.split(sys.argv[0],os.sep)[-1]
sys.stderr.write("""*** %s *** (C) by Michael Stroeder, 1999
usage: %s [options]
Options:
-h or --help
Print out this message
--config=[pathname]
Pathname of OpenSSL configuration file.
You may also use env variable OPENSSL_CONF.
Default: /etc/pyca/openssl.cnf
--pycalib=[directory]
Specify directory containing the pyCA modules
Default: /usr/share/pyca/pylib
""" % (script_name,script_name))
if ErrorMsg:
sys.stderr.write('Error: %s\n' % ErrorMsg)
sys.exit(ErrorCode)
########################################################################
# Main
########################################################################
script_name=sys.argv[0]
try:
options,args=getopt.getopt(sys.argv[1:],'h',['help','config=','pycalib='])
except getopt.error,e:
PrintUsage(str(e))
if findoption(options,'-h')!=() or findoption(options,'--help')!=():
PrintUsage()
if findoption(options,'--config')!=():
opensslcnfname = findoption(options,'--config')[1]
else:
opensslcnfname = os.environ.get('OPENSSL_CONF','/etc/pyca/openssl.cnf')
if not os.path.isfile(opensslcnfname):
PrintUsage('Config file %s not found.' % (opensslcnfname))
if findoption(options,'--pycalib')!=():
pycalib = findoption(options,'--pycalib')[1]
else:
pycalib = os.environ.get('PYCALIB','/usr/share/pyca/pylib')
if not os.path.exists(pycalib) or not os.path.isdir(pycalib):
PrintUsage('Module directory %s not exists or not a directory.' % (pycalib))
sys.path.append(pycalib)
try:
import openssl, charset
except ImportError:
PrintUsage('Required pyCA modules not found in directory %s!' % (pycalib))
# Read the configuration file
if os.path.isfile('%s.pickle' % (opensslcnfname)):
# Try to read OpenSSL's config file from a pickled copy
f=open('%s.pickle' % (opensslcnfname),'rb')
try:
# first try to use the faster cPickle module
from cPickle import load
except ImportError:
from pickle import load
opensslcnf=load(f)
f.close()
else:
# Parse OpenSSL's config file from source
opensslcnf=openssl.cnf.OpenSSLConfigClass(opensslcnfname)
pyca_section = opensslcnf.data.get('pyca',{})
openssl.bin_filename = pyca_section.get('OpenSSLExec','/usr/bin/openssl')
if not os.path.isfile(openssl.bin_filename):
PrintUsage('Did not find OpenSSL executable %s.' % (openssl.bin_filename))
OpenSSLExec = openssl.bin_filename
currentusername = pwd.getpwuid(os.getuid())[0]
# Getting UIDs
# Set current UID as default
uidCAAdmin = pwd.getpwnam(pyca_section.get('userCAAdmin',currentusername))[2]
uidMailDaemon = pwd.getpwnam(pyca_section.get('userMailDaemon',currentusername))[2]
uidWWWRun = pwd.getpwnam(pyca_section.get('userWWWRun',currentusername))[2]
gidCAAdmin = pwd.getpwuid(uidCAAdmin)[3]
gidMailDaemon = pwd.getpwuid(uidMailDaemon)[3]
gidWWWRun = pwd.getpwuid(uidWWWRun)[3]
ca_names = opensslcnf.sectionkeys.get('ca',[])
sys.stdout.write("""
#############################################################
# Create directories and various files
#############################################################
""")
for ca_name in ca_names:
sys.stdout.write('\nProcessing %s\n' % ca_name)
ca = opensslcnf.getcadata(ca_name)
# Create sub-directories
CheckedMakeDir(ca.dir,perms=0755,uid=uidCAAdmin,gid=gidCAAdmin)
CheckedMakeDir(ca.certs,perms=0755,uid=uidCAAdmin,gid=gidCAAdmin)
CheckedMakeDir(ca.new_certs_dir,perms=0700,uid=uidCAAdmin,gid=gidCAAdmin)
CheckedMakeDir(ca.crl_dir,perms=0755,uid=uidCAAdmin,gid=gidCAAdmin)
if ca.pend_reqs_dir==ca.new_reqs_dir:
CheckedMakeDir(ca.new_reqs_dir,perms=0370,uid=uidWWWRun,gid=gidCAAdmin)
else:
CheckedMakeDir(ca.pend_reqs_dir,perms=0370,uid=uidWWWRun,gid=gidMailDaemon)
CheckedMakeDir(ca.new_reqs_dir,perms=0370,uid=uidMailDaemon,gid=gidCAAdmin)
CheckedMakeDir(ca.old_reqs_dir,perms=0700,uid=uidCAAdmin,gid=gidCAAdmin)
CheckedMakeDir(os.path.dirname(ca.certificate),perms=0755,uid=uidCAAdmin,gid=gidCAAdmin)
if os.path.isfile(ca.certificate):
# In any case we set permission and ownership of
# CA certificate file if already existent
os.chown(ca.certificate,uidCAAdmin,gidCAAdmin)
os.chmod(ca.certificate,0444)
CheckedMakeDir(os.path.dirname(ca.private_key),perms=0700,uid=uidCAAdmin,gid=gidCAAdmin)
if os.path.isfile(ca.private_key):
# In any case we set permission and ownership of
# CA private key file if existent
os.chown(ca.private_key,uidCAAdmin,gidCAAdmin)
os.chmod(ca.private_key,0400)
# database: database index file
if not os.path.isfile(ca.database):
sys.stdout.write('Creating database file %s\n' % (ca.database))
file=open(ca.database,'w')
file.write('')
file.close()
os.chown(ca.database,uidCAAdmin,gidCAAdmin)
os.chmod(ca.database,0644)
# serial: next serial number for issueing certificates
if filenotvalid(ca.serial):
sys.stdout.write('Creating serial file %s\n' % (ca.serial))
file=open(ca.serial,'w')
file.write('01\n')
file.close()
os.chown(ca.serial,uidCAAdmin,gidCAAdmin)
os.chmod(ca.serial,0600)
os.setgid(gidCAAdmin)
os.setuid(uidCAAdmin)
sys.stdout.write("""
#############################################################
# create self-signed CA certs or certificate requests
#############################################################\n
Give passwords for each CAs here.
""")
subca = []
for ca_name in ca_names:
sys.stdout.write('\nProcessing %s\n' % ca_name)
ca = opensslcnf.getcadata(ca_name)
if ca.signedby:
# Add CA to list of sub-CAs to be signed late
subca.append(ca_name)
if filenotvalid('%s-req' % ca.certificate) and filenotvalid(ca.private_key):
sys.stdout.write('Creating certificate request %s with private key %s.\n' % (ca.certificate,ca.private_key))
if not ca.ca_reqfile:
ca.ca_reqfile = ca.ca_x509_extfile
if not ca.ca_reqfile:
ca.ca_reqfile = opensslcnfname
rc = os.system('%s req -config %s -new -outform pem -out %s-req -keyout %s' % \
(OpenSSLExec,ca.ca_reqfile,ca.certificate,ca.private_key))
os.chmod(ca.private_key,0400)
if rc:
sys.stderr.write('Error %d creating CA cert request %s-req.\n' % (rc,ca.certificate))
if filenotvalid(ca.certificate) and not ca.signedby:
sys.stdout.write('How many days should this certificate be valid (minimum=%d, default=%d days): ' % (ca.default_days+1,2*ca.default_days+1))
days = string.strip(sys.stdin.readline())
if not days:
days = 2*ca.default_days+1
rc = os.system('%s x509 -req -inform pem -in %s-req -outform pem -out %s -signkey %s -days %s -extfile %s' % \
(OpenSSLExec,ca.certificate,ca.certificate,ca.private_key,days,ca.ca_x509_extfile))
if rc:
sys.stderr.write('Error %d self-signing CA cert %s.\n' % (rc,ca.certificate))
if subca:
sys.stdout.write("""
#############################################################
# Create certs of sub-CAs
#############################################################\n
Use passwords of parent CAs here.\n
""")
for ca_name in subca:
sys.stdout.write('\nProcessing %s\n' % ca_name)
# Get the sub-CA's config data
subca = opensslcnf.getcadata(ca_name)
# Check if signedby points to a valid CA section name
if not subca.signedby in ca_names:
sys.stderr.write('CA name "%s" given in signedby parameter of section [%s] not found.\n' % (subca.signedby,subca.sectionname))
sys.exit(1)
# Get the issuer's CA config data
ca = opensslcnf.getcadata(subca.signedby)
# Check if issuer's certificate and key files are present
if filenotvalid(ca.certificate) or filenotvalid(ca.private_key):
sys.stderr.write("""CA certificate or key file of issuer %s not found or zero-length.
Check the files %s and %s.
""" % (subca.signedby,ca.certificate,ca.private_key))
sys.exit(1)
# Check if issuer certificate is valid at current time
gmt = time.time()
ca_cert = openssl.cert.X509CertificateClass(ca.certificate)
if gmt+86400*ca.default_days>ca_cert.notAfter_secs:
sys.stderr.write("""Certificate of issueing parent CA "%s" is not valid until %s.
You can either set parameter default_days<=%d in section [%s] or
issue a new parent CA cert.
""" % (ca.name,time.strftime('%Y-%m-%d %H:%M',time.gmtime(gmt+86400*ca.default_days)),(ca_cert.notAfter_secs-gmt)/86400,ca.sectionname))
sys.exit(1)
# Create the new sub-CA certificate if there's no older file in the way
if filenotvalid(subca.certificate):
sys.stdout.write('Creating sub-CA certificate %s with issuer "%s".\n' % (subca.certificate,ca.name))
rc = os.system('%s x509 -req -inform pem -in %s-req -outform pem -out %s -CA %s -CAkey %s -CAserial %s -days %s -extfile %s' % \
(OpenSSLExec,subca.certificate,subca.certificate,ca.certificate,ca.private_key,ca.serial,ca.default_days,subca.ca_x509_extfile))
if rc:
sys.stderr.write('Error %d issueing CA cert %s.\n' % (rc,ca.certificate))
else:
sys.stdout.write('Sub-CA certificate file %s already exists. Skipping...\n' % (subca.certificate))
sys.stdout.write("""
#############################################################
# Verifying CA certs
#############################################################\n
""")
for ca_name in ca_names:
ca = opensslcnf.getcadata(ca_name)
if ca.signedby:
if ca.signedby in ca_names:
parentca = opensslcnf.getcadata(ca.signedby)
else:
parentca = None
sys.stderr.write('CA name "%s" given in signedby parameter of section [%s] not found.\n' % (subca.signedby,subca.sectionname))
else:
parentca = ca
if not (filenotvalid(ca.certificate) or filenotvalid(parentca.certificate)):
sys.stdout.write('Verifying sub-CA certificate %s with issuer certificate %s.\n' % (ca.certificate,parentca.certificate))
rc = os.system('%s verify -verbose -CAfile %s %s' % \
(OpenSSLExec,parentca.certificate,ca.certificate))
if rc:
sys.stderr.write('Error %d verifying CA cert %s.\n' % (rc,ca.certificate))
ca_cert = openssl.cert.X509CertificateClass(ca.certificate)
if not ca_cert.subject.has_key('CN'):
sys.stderr.write('CA certificate %s has no CN attribute.\nThis might cause weird problems with some software.\n' % (ca.certificate))
for subject_attr in ca_cert.subject.keys():
if not charset.is_ascii(charset.asn12iso(ca_cert.subject[subject_attr])):
sys.stderr.write('CA certificate %s has NON-ASCII attribute %s.\nThis might cause weird problems with some software.\n' % (ca.certificate,subject_attr))
else:
sys.stderr.write('Certificate file %s or %s not found.\n' % (ca.certificate,parentca.certificate))
|