Convert the setup of ssl from a shell script to a

python module. This is in preparation for user
supplied certs.
This commit is contained in:
Karl MacMillan 0001-01-01 00:00:00 +00:00
parent ad3fcc200c
commit 3b4f0db73e
7 changed files with 245 additions and 229 deletions

View File

@ -27,6 +27,7 @@ from random import Random
from time import gmtime
import os, sys, traceback, readline
import stat
import shutil
from types import *
@ -101,6 +102,15 @@ def dir_exists(filename):
except:
return False
def install_file(fname, dest):
if file_exists(dest):
os.rename(dest, dest + ".orig")
shutil.move(fname, dest)
def backup_file(fname):
if file_exists(fname):
os.rename(fname, fname + ".orig")
class CIDict(dict):
"""
Case-insensitive but case-respecting dictionary.

View File

@ -10,14 +10,8 @@ sbin_SCRIPTS = \
ipa-replica-prepare \
$(NULL)
appdir = $(IPA_DATA_DIR)
app_SCRIPTS = \
ipa-server-setupssl \
$(NULL)
EXTRA_DIST = \
README \
$(app_SCRIPTS) \
$(sbin_SCRIPTS) \
$(NULL)

View File

@ -1,216 +0,0 @@
#!/bin/bash
if [ "$1" ] ; then
password=$1
else
echo "password required"
exit 1
fi
if [ "$2" -a -d "$2" ] ; then
secdir="$2"
else
secdir=/etc/dirsrv/slapd-localhost
fi
if [ "$3" ] ; then
myhost=$3
else
myhost=`hostname --fqdn`
fi
if [ "$4" ] ; then
ldapport=$4
else
ldapport=389
fi
me=`whoami`
if [ "$me" = "root" ] ; then
isroot=1
fi
# see if there are already certs and keys
if [ -f $secdir/cert8.db ] ; then
# look for CA cert
if certutil -L -d $secdir -n "CA certificate" 2> /dev/null ; then
echo "Using existing CA certificate"
else
echo "No CA certificate found - will create new one"
needCA=1
fi
# look for server cert
if certutil -L -d $secdir -n "Server-Cert" 2> /dev/null ; then
echo "Using existing directory Server-Cert"
else
echo "No Server Cert found - will create new one"
needServerCert=1
fi
prefix="new-"
prefixarg="-P $prefix"
else
needCA=1
needServerCert=1
fi
if test -z "$needCA" -a -z "$needServerCert" ; then
echo "No certs needed - exiting"
exit 0
fi
# get our user and group
if test -n "$isroot" ; then
uid=`/bin/ls -ald $secdir | awk '{print $3}'`
gid=`/bin/ls -ald $secdir | awk '{print $4}'`
fi
# 2. Create a password file for your security token password:
if [ -f $secdir/pwdfile.txt ] ; then
echo "Using existing $secdir/pwdfile.txt"
else
(ps -ef ; w ) | sha1sum | awk '{print $1}' > $secdir/pwdfile.txt
if test -n "$isroot" ; then
chown $uid:$gid $secdir/pwdfile.txt
fi
chmod 400 $secdir/pwdfile.txt
fi
# 3. Create a "noise" file for your encryption mechanism:
if [ -f $secdir/noise.txt ] ; then
echo "Using existing $secdir/noise.txt file"
else
(w ; ps -ef ; date ) | sha1sum | awk '{print $1}' > $secdir/noise.txt
if test -n "$isroot" ; then
chown $uid:$gid $secdir/noise.txt
fi
chmod 400 $secdir/noise.txt
fi
# 4. Create the key3.db and cert8.db databases:
certutil -N $prefixarg -d $secdir -f $secdir/pwdfile.txt
if test -n "$isroot" ; then
chown $uid:$gid $secdir/${prefix}key3.db $secdir/${prefix}cert8.db
fi
chmod 600 $secdir/${prefix}key3.db $secdir/${prefix}cert8.db
if test -n "$needCA" ; then
# 5. Generate the encryption key:
certutil -G $prefixarg -d $secdir -z $secdir/noise.txt -f $secdir/pwdfile.txt
# 6. Generate the self-signed certificate:
certutil -S $prefixarg -n "CA certificate" -s "cn=CAcert" -x -t "CT,," -m 1000 -v 120 -d $secdir -z $secdir/noise.txt -f $secdir/pwdfile.txt
# export the CA cert for use with other apps
certutil -L $prefixarg -d $secdir -n "CA certificate" -a > $secdir/cacert.asc
pk12util -d $secdir $prefixarg -o $secdir/cacert.p12 -n "CA certificate" -w $secdir/pwdfile.txt -k $secdir/pwdfile.txt
fi
if test -n "$needServerCert" ; then
# 7. Generate the server certificate:
certutil -S $prefixarg -n "Server-Cert" -s "cn=$myhost,ou=Fedora Directory Server" -c "CA certificate" -t "u,u,u" -m 1001 -v 120 -d $secdir -z $secdir/noise.txt -f $secdir/pwdfile.txt
fi
# create the pin file
if [ ! -f $secdir/pin.txt ] ; then
pinfile=$secdir/pin.txt
echo 'Internal (Software) Token:'`cat $secdir/pwdfile.txt` > $pinfile
if test -n "$isroot" ; then
chown $uid:$gid $pinfile
fi
chmod 400 $pinfile
else
echo Using existing $secdir/pin.txt
fi
if [ -n "$prefix" ] ; then
# move the old files out of the way
mv $secdir/cert8.db $secdir/orig-cert8.db
mv $secdir/key3.db $secdir/orig-key3.db
# move in the new files - will be used after server restart
mv $secdir/${prefix}cert8.db $secdir/cert8.db
mv $secdir/${prefix}key3.db $secdir/key3.db
fi
modnssdir=/etc/httpd/alias
# Setup SSL in Apache
if [ -e $modnssdir ]; then
mkdir ${modnssdir}.ipa
mv $modnssdir/cert8.db ${modnssdir}.ipa
mv $modnssdir/key3.db ${modnssdir}.ipa
fi
# Create a new database for mod_nss
echo -e "\n" > $modnssdir/pw.txt
certutil -N -d $modnssdir -f $modnssdir/pw.txt
# Add the CA we created
certutil -A -d $modnssdir -n "CA certificate" -t "CT,CT," -a -i $secdir/cacert.asc
# Request a new server cert
certutil -R -d $modnssdir \
-s "cn=$myhost,ou=Apache Web Server" \
-o $modnssdir/tmpcertreq \
-g 1024 \
-z $secdir/noise.txt \
-f $modnssdir/pw.txt
# Have the FDS CA issue the cert
echo -e "2\n9\nn\n1\n9\nn\n" | \
certutil -C -d $secdir \
-c "CA certificate" \
-i $modnssdir/tmpcertreq \
-o $modnssdir/tmpcert.der \
-m 1002 \
-v 120 \
-f $secdir/pwdfile.txt \
-1 \
-5
# Now add this cert to the Apache database
certutil -A -d $modnssdir -n "Server-Cert"\
-t u,u,u \
-i $modnssdir/tmpcert.der \
-f $modnsdir/tmpcert.der
rm -f $modnssdir/pw.txt $modnssdir/tmpcertreq $modnssder/tmpcert.der
# enable SSL in the directory server
ldapmodify -x -h localhost -p $ldapport -D "cn=Directory Manager" -w $password <<EOF
dn: cn=encryption,cn=config
changetype: modify
replace: nsSSL3
nsSSL3: on
-
replace: nsSSLClientAuth
nsSSLClientAuth: allowed
-
add: nsSSL3Ciphers
nsSSL3Ciphers: -rsa_null_md5,+rsa_rc4_128_md5,+rsa_rc4_40_md5,+rsa_rc2_40_md5,
+rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,
+fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,
+tls_rsa_export1024_with_des_cbc_sha
dn: cn=config
changetype: modify
add: nsslapd-security
nsslapd-security: on
-
replace: nsslapd-ssl-check-hostname
nsslapd-ssl-check-hostname: off
dn: cn=RSA,cn=encryption,cn=config
changetype: add
objectclass: top
objectclass: nsEncryptionModule
cn: RSA
nsSSLPersonalitySSL: Server-Cert
nsSSLToken: internal (software)
nsSSLActivation: on
EOF

View File

@ -14,6 +14,7 @@ app_PYTHON = \
service.py \
installutils.py \
replication.py \
certs.py \
$(NULL)
EXTRA_DIST = \

View File

@ -0,0 +1,192 @@
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
#
# Copyright (C) 2007 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 or later
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import os, stat, subprocess
import sha
from ipa import ipautil
class CertDB(object):
def __init__(self, dir):
self.secdir = dir
self.prefix = "new-"
self.noise_fname = self.secdir + "/noise.txt"
self.passwd_fname = self.secdir + "/pwdfile.txt"
self.certdb_fname = self.secdir + "/cert8.db"
self.keydb_fname = self.secdir + "/key3.db"
self.cacert_fname = self.secdir + "/cacert.asc"
self.pk12_fname = self.secdir + "/cacert.p12"
self.pin_fname = self.secdir + "/pin.txt"
self.certreq_fname = self.secdir + "/tmpcertreq"
self.certder_fname = self.secdir + "/tmpcert.der"
# We are going to set the owner of all of the cert
# files to the owner of the containing directory
# instead of that of the process. This works when
# this is called by root for a daemon that runs as
# a normal user
mode = os.stat(self.secdir)
self.uid = mode[stat.ST_UID]
self.gid = mode[stat.ST_GID]
def set_perms(self, fname, write=False):
os.chown(fname, self.uid, self.gid)
perms = stat.S_IRUSR
if write:
perms |= stat.S_IWUSR
os.chmod(fname, perms)
def gen_password(self):
return sha.sha(ipautil.ipa_generate_password()).hexdigest()
def run_certutil(self, args, stdin=None):
new_args = ["/usr/bin/certutil", "-d", self.secdir]
new_args = new_args + args
ipautil.run(new_args, stdin)
def create_noise_file(self):
ipautil.backup_file(self.noise_fname)
f = open(self.noise_fname, "w")
f.write(self.gen_password())
self.set_perms(self.noise_fname)
def create_passwd_file(self, passwd=True):
ipautil.backup_file(self.passwd_fname)
f = open(self.passwd_fname, "w")
if passwd:
f.write(self.gen_password())
else:
f.write("\n")
f.close()
self.set_perms(self.passwd_fname)
def create_certdbs(self):
ipautil.backup_file(self.certdb_fname)
ipautil.backup_file(self.keydb_fname)
self.run_certutil(["-N",
"-f", self.passwd_fname])
self.set_perms(self.passwd_fname, write=True)
def create_ca_cert(self):
# Generate the encryption key
self.run_certutil(["-G", "-z", self.noise_fname, "-f", self.passwd_fname])
# Generate the self-signed cert
self.run_certutil(["-S", "-n", "CA certificate",
"-s", "cn=CAcert",
"-x",
"-t", "CT,,",
"-m", "1000",
"-v", "120",
"-z", self.noise_fname,
"-f", self.passwd_fname])
# export the CA cert for use with other apps
ipautil.backup_file(self.cacert_fname)
self.run_certutil(["-L", "-n", "CA certificate",
"-a",
"-o", self.cacert_fname])
self.set_perms(self.cacert_fname)
ipautil.backup_file(self.pk12_fname)
ipautil.run(["/usr/bin/pk12util", "-d", self.secdir,
"-o", self.pk12_fname,
"-n", "CA certificate",
"-w", self.passwd_fname,
"-k", self.passwd_fname])
self.set_perms(self.pk12_fname)
def load_cacert(self, cacert_fname):
self.run_certutil(["-A", "-n", "CA certificate",
"-t", "CT,CT,",
"-a",
"-i", cacert_fname])
def create_server_cert(self, nickname, name):
self.run_certutil(["-S", "-n", nickname,
"-s", name,
"-c", "CA certificate",
"-t", "u,u,u",
"-m", "1001",
"-v", "120",
"-z", self.noise_fname,
"-f", self.passwd_fname])
def request_cert(self, name):
self.run_certutil(["-R", "-s", name,
"-o", self.certreq_fname,
"-g", "1024",
"-z", self.noise_fname,
"-f", self.passwd_fname])
def issue_cert(self, certreq_fname, cert_fname):
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-C", "-c", "CA certificate",
"-i", certreq_fname,
"-o", cert_fname,
"-m", "1002",
"-v", "120",
"-f", self.passwd_fname,
"-1", "-5"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
# bah - this sucks, but I guess it isn't possible to fully
# control this with command line arguments
p.stdin.write("2\n9\nn\n1\n9\nn\n")
p.wait()
def add_cert(self, cert_fname, nickname):
self.run_certutil(["-A", "-n", nickname,
"-t", "u,u,u",
"-i", cert_fname,
"-f", cert_fname])
def create_server_cert_extca(self, nickname, name, other_certdb):
self.request_cert(name)
other_certdb.issue_cert(self.certreq_fname, self.certder_fname)
self.add_cert(self.certder_fname, nickname)
os.unlink(self.certreq_fname)
os.unlink(self.certder_fname)
def create_pin_file(self):
ipautil.backup_file(self.pin_fname)
f = open(self.pin_fname, "w")
f.write("Internal (Software) Token:")
pwd = open(self.passwd_fname)
f.write(pwd.read())
f.close()
self.set_perms(self.pin_fname)
def create_self_signed(self, passwd=True):
self.create_noise_file()
self.create_passwd_file(passwd)
self.create_certdbs()
self.create_ca_cert()
self.create_pin_file()
def create_from_cacert(self, cacert_fname, passwd=False):
self.create_noise_file()
self.create_passwd_file(passwd)
self.create_certdbs()
self.load_cacert(cacert_fname)

View File

@ -29,6 +29,8 @@ from ipa import ipautil
import service
import installutils
import certs
import ipaldap, ldap
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
SERVER_ROOT_32 = "/usr/lib/dirsrv"
@ -290,13 +292,36 @@ class DsInstance(service.Service):
def __enable_ssl(self):
self.step("configuring ssl for ds instance")
dirname = config_dirname(self.realm_name)
args = ["/usr/share/ipa/ipa-server-setupssl", self.dm_password,
dirname, self.host_name]
try:
ipautil.run(args)
logging.debug("done configuring ssl for ds instance")
except ipautil.CalledProcessError, e:
logging.critical("Failed to configure ssl in ds instance %s" % e)
ca = certs.CertDB(dirname)
ca.create_self_signed()
ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name)
conn = ipaldap.IPAdmin("127.0.0.1")
conn.simple_bind_s("cn=directory manager", self.dm_password)
mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"),
(ldap.MOD_REPLACE, "nsSSL3Ciphers",
"-rsa_null_md5,+rsa_rc4_128_md5,+rsa_rc4_40_md5,+rsa_rc2_40_md5,\
+rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,\
+fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,\
+tls_rsa_export1024_with_des_cbc_sha")]
conn.modify_s("cn=encryption,cn=config", mod)
mod = [(ldap.MOD_ADD, "nsslapd-security", "on"),
(ldap.MOD_REPLACE, "nsslapd-ssl-check-hostname", "off")]
conn.modify_s("cn=config", mod)
entry = ipaldap.Entry("cn=RSA,cn=encryption,cn=config")
entry.setValues("objectclass", "top", "nsEncryptionModule")
entry.setValues("cn", "RSA")
entry.setValues("nsSSLPersonalitySSL", "Server-Cert")
entry.setValues("nsSSLToken", "internal (software)")
entry.setValues("nsSSLActivation", "on")
conn.addEntry(entry)
conn.unbind()
def __add_default_layout(self):
self.step("adding default layout")

View File

@ -27,6 +27,8 @@ import sys
import time
import service
import certs
import dsinstance
from ipa.ipautil import *
HTTPD_DIR = "/etc/httpd"
@ -143,3 +145,11 @@ class HTTPInstance(service.Service):
self.step("Setting mod_nss port to 443")
if update_file(NSS_CONF, '8443', '443') != 0:
print "Updating %s failed." % NSS_CONF
def __setup_ssl(self):
self.step("Setting up ssl")
ds_ca = certs.CertDB(dsinstance.config_dirname(self.realm))
ca = certs.CertDB(dirname)
ca.create_from_cacert(ds_ca.cacert_fname)
ca.create_server_cert_extca("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca)