summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/share/Makefile.am1
-rw-r--r--install/share/caJarSigningCert.cfg.template88
-rw-r--r--ipaserver/install/cainstance.py40
-rw-r--r--ipaserver/install/certs.py149
-rw-r--r--ipaserver/install/httpinstance.py9
-rw-r--r--ipaserver/install/installutils.py29
6 files changed, 259 insertions, 57 deletions
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index 6ef43ba..3a2ef87 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -10,6 +10,7 @@ app_DATA = \
60basev2.ldif \
60policyv2.ldif \
bootstrap-template.ldif \
+ caJarSigningCert.cfg.template \
default-aci.ldif \
default-keytypes.ldif \
kerberos.ldif \
diff --git a/install/share/caJarSigningCert.cfg.template b/install/share/caJarSigningCert.cfg.template
new file mode 100644
index 0000000..9f01855
--- /dev/null
+++ b/install/share/caJarSigningCert.cfg.template
@@ -0,0 +1,88 @@
+desc=Jar Signing certificate to auto-configure Firefox
+enable=true
+enableBy=admin
+lastModified=1239836280692
+name=Manual Jar Signing Certificate Enrollment
+visible=true
+auth.class_id=
+auth.instance_id=raCertAuth
+input.list=i1,i2
+input.i1.class_id=certReqInputImpl
+input.i2.class_id=submitterInfoInputImpl
+output.list=o1
+output.o1.class_id=certOutputImpl
+policyset.list=caJarSigningSet
+policyset.caJarSigningSet.list=1,2,3,6,7,9
+policyset.caJarSigningSet.1.constraint.class_id=subjectNameConstraintImpl
+policyset.caJarSigningSet.1.constraint.name=Subject Name Constraint
+policyset.caJarSigningSet.1.constraint.params.accept=true
+policyset.caJarSigningSet.1.constraint.params.pattern=.*
+policyset.caJarSigningSet.1.default.class_id=userSubjectNameDefaultImpl
+policyset.caJarSigningSet.1.default.name=Subject Name Default
+policyset.caJarSigningSet.1.default.params.name=
+policyset.caJarSigningSet.2.constraint.class_id=validityConstraintImpl
+policyset.caJarSigningSet.2.constraint.name=Validity Constraint
+policyset.caJarSigningSet.2.constraint.params.notAfterCheck=false
+policyset.caJarSigningSet.2.constraint.params.notBeforeCheck=false
+policyset.caJarSigningSet.2.constraint.params.range=2922
+policyset.caJarSigningSet.2.default.class_id=validityDefaultImpl
+policyset.caJarSigningSet.2.default.name=Validity Default
+policyset.caJarSigningSet.2.default.params.range=1461
+policyset.caJarSigningSet.2.default.params.startTime=60
+policyset.caJarSigningSet.3.constraint.class_id=keyConstraintImpl
+policyset.caJarSigningSet.3.constraint.name=Key Constraint
+policyset.caJarSigningSet.3.constraint.params.keyMaxLength=4096
+policyset.caJarSigningSet.3.constraint.params.keyMinLength=1024
+policyset.caJarSigningSet.3.constraint.params.keyType=-
+policyset.caJarSigningSet.3.default.class_id=userKeyDefaultImpl
+policyset.caJarSigningSet.3.default.name=Key Default
+policyset.caJarSigningSet.6.constraint.class_id=keyUsageExtConstraintImpl
+policyset.caJarSigningSet.6.constraint.name=Key Usage Extension Constraint
+policyset.caJarSigningSet.6.constraint.params.keyUsageCritical=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageCrlSign=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageDataEncipherment=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageDecipherOnly=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageDigitalSignature=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageEncipherOnly=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageKeyAgreement=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageKeyCertSign=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageKeyEncipherment=-
+policyset.caJarSigningSet.6.constraint.params.keyUsageNonRepudiation=-
+policyset.caJarSigningSet.6.default.class_id=keyUsageExtDefaultImpl
+policyset.caJarSigningSet.6.default.name=Key Usage Default
+policyset.caJarSigningSet.6.default.params.keyUsageCritical=true
+policyset.caJarSigningSet.6.default.params.keyUsageCrlSign=false
+policyset.caJarSigningSet.6.default.params.keyUsageDataEncipherment=false
+policyset.caJarSigningSet.6.default.params.keyUsageDecipherOnly=false
+policyset.caJarSigningSet.6.default.params.keyUsageDigitalSignature=true
+policyset.caJarSigningSet.6.default.params.keyUsageEncipherOnly=false
+policyset.caJarSigningSet.6.default.params.keyUsageKeyAgreement=false
+policyset.caJarSigningSet.6.default.params.keyUsageKeyCertSign=true
+policyset.caJarSigningSet.6.default.params.keyUsageKeyEncipherment=false
+policyset.caJarSigningSet.6.default.params.keyUsageNonRepudiation=false
+policyset.caJarSigningSet.7.constraint.class_id=nsCertTypeExtConstraintImpl
+policyset.caJarSigningSet.7.constraint.name=Netscape Certificate Type Extension Constraint
+policyset.caJarSigningSet.7.constraint.params.nsCertCritical=-
+policyset.caJarSigningSet.7.constraint.params.nsCertEmail=-
+policyset.caJarSigningSet.7.constraint.params.nsCertEmailCA=-
+policyset.caJarSigningSet.7.constraint.params.nsCertObjectSigning=-
+policyset.caJarSigningSet.7.constraint.params.nsCertObjectSigningCA=-
+policyset.caJarSigningSet.7.constraint.params.nsCertSSLCA=-
+policyset.caJarSigningSet.7.constraint.params.nsCertSSLClient=-
+policyset.caJarSigningSet.7.constraint.params.nsCertSSLServer=-
+policyset.caJarSigningSet.7.default.class_id=nsCertTypeExtDefaultImpl
+policyset.caJarSigningSet.7.default.name=Netscape Certificate Type Extension Default
+policyset.caJarSigningSet.7.default.params.nsCertCritical=false
+policyset.caJarSigningSet.7.default.params.nsCertEmail=false
+policyset.caJarSigningSet.7.default.params.nsCertEmailCA=false
+policyset.caJarSigningSet.7.default.params.nsCertObjectSigning=true
+policyset.caJarSigningSet.7.default.params.nsCertObjectSigningCA=false
+policyset.caJarSigningSet.7.default.params.nsCertSSLCA=false
+policyset.caJarSigningSet.7.default.params.nsCertSSLClient=false
+policyset.caJarSigningSet.7.default.params.nsCertSSLServer=false
+policyset.caJarSigningSet.9.constraint.class_id=signingAlgConstraintImpl
+policyset.caJarSigningSet.9.constraint.name=No Constraint
+policyset.caJarSigningSet.9.constraint.params.signingAlgsAllowed=MD5withRSA,MD2withRSA,SHA1withRSA,SHA256withRSA,SHA512withRSA,SHA1withDSA,SHA1withEC
+policyset.caJarSigningSet.9.default.class_id=signingAlgDefaultImpl
+policyset.caJarSigningSet.9.default.name=Signing Alg
+policyset.caJarSigningSet.9.default.params.signingAlg=-
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 088744a..d33901d 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -34,6 +34,7 @@ import shutil
import httplib
import urllib
import xml.dom.minidom
+import stat
from nss.error import NSPRError
import nss.nss as nss
@@ -44,7 +45,6 @@ from ipapython import nsslib
from ipaserver.install import service
from ipaserver.install import installutils
from ipaserver import ipaldap
-from ipaserver.install import ldapupdate
from ipaserver.install import dsinstance
from ipalib import util
@@ -368,6 +368,7 @@ class CAInstance(service.Service):
self.server_root = "/var/lib"
self.secure_port = 9444
self.ra_cert = None
+ self.requestId = None
def __del__(self):
shutil.rmtree(self.ca_agent_db, ignore_errors=True)
@@ -390,6 +391,7 @@ class CAInstance(service.Service):
self.step("issuing RA agent certificate", self.__issue_ra_cert)
self.step("adding RA agent as a trusted user", self.__configure_ra)
self.step("fixing RA database permissions", self.__fix_ra_perms)
+ self.step("setting up signing cert profile", self.__setup_sign_profile)
self.step("configuring certificate server to start on boot", self.__enable)
self.step("restarting certificate server", self.__restart_instance)
@@ -540,7 +542,7 @@ class CAInstance(service.Service):
def __restart_instance(self):
try:
self.restart()
- except Exception:
+ except Exception, e:
# TODO: roll back here?
logging.critical("Failed to restart the certificate server. See the installation log for details.")
@@ -577,9 +579,10 @@ class CAInstance(service.Service):
'-n', 'ipa-ca-agent',
'-p', self.admin_password,
'-d', self.ca_agent_db,
- '-r', '/ca/agent/ca/profileReview?requestId=7',
+ '-r', '/ca/agent/ca/profileReview?requestId=%s' % self.requestId,
'%s:%d' % (self.host_name, 9443),
]
+ logging.debug("running sslget %s" % args)
(stdout, stderr) = ipautil.run(args)
data = stdout.split('\r\n')
@@ -589,6 +592,8 @@ class CAInstance(service.Service):
params['submit'] = 'submit'
params['requestNotes'] = ''
params = urllib.urlencode(params)
+ headers = {"Content-type": "application/x-www-form-urlencoded",
+ "Accept": "text/plain"}
# Now issue the RA certificate.
args = [
@@ -600,6 +605,7 @@ class CAInstance(service.Service):
'-r', '/ca/agent/ca/profileProcess',
'%s:%d' % (self.host_name, 9443),
]
+ logging.debug("running sslget %s" % args)
(stdout, stderr) = ipautil.run(args)
data = stdout.split('\r\n')
@@ -679,6 +685,7 @@ class CAInstance(service.Service):
f = os.open(self.ra_agent_pwd, os.O_CREAT | os.O_RDWR)
os.write(f, hex_str)
os.close(f)
+ os.chmod(self.ra_agent_pwd, stat.S_IRUSR)
stdout, stderr = self.__run_certutil(["-N"])
@@ -758,11 +765,14 @@ class CAInstance(service.Service):
res = conn.getresponse()
if res.status == 200:
data = res.read()
- # FIXME: pull the requestId out so of the response so it isn't
- # later hard-coded at 7
-# print data
-
conn.close()
+ doc = xml.dom.minidom.parseString(data)
+ item_node = doc.getElementsByTagName("RequestId")
+ self.requestId = item_node[0].childNodes[0].data
+ doc.unlink()
+ self.requestId = self.requestId.strip()
+ if self.requestId is None:
+ raise RuntimeError("Unable to determine RA certificate requestId")
else:
conn.close()
raise RuntimeError("Unable to submit RA cert request")
@@ -778,6 +788,22 @@ class CAInstance(service.Service):
os.chown(self.ra_agent_db + "/secmod.db", 0, pent.pw_gid )
os.chown(self.ra_agent_pwd, 0, pent.pw_gid)
+ def __setup_sign_profile(self):
+ caconfig = "/var/lib/pki-ca/conf/CS.cfg"
+
+ if not ipautil.file_exists('/var/lib/pki-ca/profiles/ca/caJarSigningCert.cfg'):
+ profile = ipautil.template_file(ipautil.SHARE_DIR + "caJarSigningCert.cfg.template", {})
+ fd = open("/var/lib/pki-ca/profiles/ca/caJarSigningCert.cfg", "w")
+ fd.write(profile)
+ fd.close()
+
+ profilelist = installutils.get_directive(caconfig, "profile.list", separator="=")
+ if profilelist.find('caJarSigningCert') < 0:
+ profilelist = profilelist + ',caJarSigningCert'
+ installutils.set_directive(caconfig, 'profile.list', profilelist, quotes=False, separator='=')
+ installutils.set_directive(caconfig, 'profile.caJarSigningCert.class_id', 'caEnrollImpl', quotes=False, separator='=')
+ installutils.set_directive(caconfig, 'profile.caJarSigningCert.config', '/var/lib/pki-ca/profiles/ca/caJarSigningCert.cfg', quotes=False, separator='=')
+
def uninstall(self):
try:
ipautil.run(["/usr/bin/pkiremove", "-pki_instance_root=/var/lib",
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 45958f2..bad9a1e 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -23,8 +23,10 @@ import errno
import tempfile
import shutil
import logging
+import httplib
import urllib
import xml.dom.minidom
+import pwd
from ipapython import nsslib
from ipapython import sysrestore
@@ -165,8 +167,12 @@ class CertDB(object):
return str(self.cur_serial)
- def set_perms(self, fname, write=False):
- os.chown(fname, self.uid, self.gid)
+ def set_perms(self, fname, write=False, uid=None):
+ if uid:
+ pent = pwd.getpwnam(uid)
+ os.chown(fname, pent.pw_uid, pent.pw_gid)
+ else:
+ os.chown(fname, self.uid, self.gid)
perms = stat.S_IRUSR
if write:
perms |= stat.S_IWUSR
@@ -181,7 +187,13 @@ class CertDB(object):
return ipautil.run(new_args, stdin)
def run_signtool(self, args, stdin=None):
- new_args = ["/usr/bin/signtool", "-d", self.secdir]
+ if not self.self_signed_ca:
+ f = open(self.passwd_fname, "r")
+ password = f.readline()
+ f.close()
+ new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password]
+ else:
+ new_args = ["/usr/bin/signtool", "-d", self.secdir]
new_args = new_args + args
ipautil.run(new_args, stdin)
@@ -233,7 +245,7 @@ class CertDB(object):
self.run_certutil(["-L", "-n", nickname,
"-a",
"-o", self.cacert_fname])
- self.set_perms(self.cacert_fname)
+ os.chmod(self.cacert_fname, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
if create_pkcs12:
ipautil.backup_file(self.pk12_fname)
ipautil.run(["/usr/bin/pk12util", "-d", self.secdir,
@@ -286,11 +298,11 @@ class CertDB(object):
os.unlink(self.certreq_fname)
os.unlink(self.certder_fname)
- def create_signing_cert(self, nickname, name, other_certdb=None):
+ def create_signing_cert(self, nickname, subject, other_certdb=None):
cdb = other_certdb
if not cdb:
cdb = self
- self.request_cert(name)
+ self.request_cert(subject)
cdb.issue_signing_cert(self.certreq_fname, self.certder_fname)
self.add_cert(self.certder_fname, nickname)
os.unlink(self.certreq_fname)
@@ -365,8 +377,8 @@ class CertDB(object):
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
- # Send the CSR request to the CA
- f = open(self.passwd_fname)
+ # Send the request to the CA
+ f = open(self.passwd_fname, "r")
password = f.readline()
f.close()
conn = nsslib.NSSConnection(self.host_name, 9444, dbdir=self.secdir)
@@ -385,6 +397,7 @@ class CertDB(object):
item_node = doc.getElementsByTagName("b64")
cert = item_node[0].childNodes[0].data
doc.unlink()
+ conn.close()
# Write the certificate to a file. It will be imported in a later
# step.
@@ -395,34 +408,87 @@ class CertDB(object):
return
def issue_signing_cert(self, certreq_fname, cert_fname):
- p = subprocess.Popen(["/usr/bin/certutil",
- "-d", self.secdir,
- "-C", "-c", self.cacert_name,
- "-i", certreq_fname,
- "-o", cert_fname,
- "-m", self.next_serial(),
- "-v", self.valid_months,
- "-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.
- #
- # What this is requesting is:
- # -1 (Create key usage extension)
- # 0 - Digital Signature
- # 5 - Cert signing key
- # 9 - done
- # n - not critical
- #
- # -5 (Create netscape cert type extension)
- # 3 - Object Signing
- # 9 - done
- # n - not critical
- p.stdin.write("0\n5\n9\nn\n3\n9\nn\n")
- p.wait()
+ if self.self_signed_ca:
+ p = subprocess.Popen(["/usr/bin/certutil",
+ "-d", self.secdir,
+ "-C", "-c", self.cacert_name,
+ "-i", certreq_fname,
+ "-o", cert_fname,
+ "-m", self.next_serial(),
+ "-v", self.valid_months,
+ "-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.
+ #
+ # What this is requesting is:
+ # -1 (Create key usage extension)
+ # 0 - Digital Signature
+ # 5 - Cert signing key
+ # 9 - done
+ # n - not critical
+ #
+ # -5 (Create netscape cert type extension)
+ # 3 - Object Signing
+ # 9 - done
+ # n - not critical
+ p.stdin.write("0\n5\n9\nn\n3\n9\nn\n")
+ p.wait()
+ else:
+ if self.host_name is None:
+ raise RuntimeError("CA Host is not set.")
+
+ f = open(certreq_fname, "r")
+ csr = f.readlines()
+ f.close()
+ csr = "".join(csr)
+
+ # We just want the CSR bits, make sure there is no thing else
+ s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----")
+ e = csr.find("-----END NEW CERTIFICATE REQUEST-----")
+ if e > 0:
+ e = e + 37
+ if s >= 0:
+ csr = csr[s:]
+
+ params = urllib.urlencode({'profileId': 'caJarSigningCert',
+ 'cert_request_type': 'pkcs10',
+ 'requestor_name': 'IPA Installer',
+ 'cert_request': csr,
+ 'xmlOutput': 'true'})
+ headers = {"Content-type": "application/x-www-form-urlencoded",
+ "Accept": "text/plain"}
+
+ # Send the request to the CA
+ f = open(self.passwd_fname, "r")
+ password = f.readline()
+ f.close()
+ conn = nsslib.NSSConnection(self.host_name, 9444, dbdir=self.secdir)
+ conn.sslsock.set_client_auth_data_callback(client_auth_data_callback, "ipaCert", password, nss.get_default_certdb())
+ conn.set_debuglevel(0)
+
+ conn.request("POST", "/ca/ee/ca/profileSubmit", params, headers)
+ res = conn.getresponse()
+ data = res.read()
+ conn.close()
+ if res.status != 200:
+ raise RuntimeError("Unable to submit cert request")
+
+ # The result is an XML blob. Pull the certificate out of that
+ doc = xml.dom.minidom.parseString(data)
+ item_node = doc.getElementsByTagName("b64")
+ cert = item_node[0].childNodes[0].data
+ doc.unlink()
+ conn.close()
+
+ f = open(cert_fname, "w")
+ f.write(cert)
+ f.close()
+
+ return
def add_cert(self, cert_fname, nickname):
args = ["-A", "-n", nickname,
@@ -440,9 +506,10 @@ class CertDB(object):
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())
+ pwdfile = open(self.passwd_fname)
+ f.write(pwdfile.read())
f.close()
+ pwdfile.close()
self.set_perms(self.pin_fname)
def create_password_conf(self):
@@ -452,9 +519,11 @@ class CertDB(object):
ipautil.backup_file(self.pwd_conf)
f = open(self.pwd_conf, "w")
f.write("internal:")
- pwd = open(self.passwd_fname)
- f.write(pwd.read())
+ pwdfile = open(self.passwd_fname)
+ f.write(pwdfile.read())
f.close()
+ pwdfile.close()
+ self.set_perms(self.pwd_conf, uid="apache")
def find_root_cert(self, nickname):
p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir,
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 0637e3f..1bd9ffd 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -183,6 +183,7 @@ class HTTPInstance(service.Service):
db.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ca_db)
else:
db.create_server_cert("Server-Cert", "CN=%s,OU=ipa-pki,O=IPA" % self.fqdn, ca_db)
+ db.create_signing_cert("Signing-Cert", "CN=Object Signing Cert,OU=ipa-pki,O=IPA", ca_db)
db.create_password_conf()
# Fix the database permissions
@@ -196,20 +197,12 @@ class HTTPInstance(service.Service):
os.chown(NSS_DIR + "/secmod.db", 0, pent.pw_gid )
def __setup_autoconfig(self):
- # FIXME. Need to issue the self-signed cert from the CA as well.
- # A special profile is needed from the CS team to do this.
- if not self.self_signed_ca:
- return
prefs_txt = ipautil.template_file(ipautil.SHARE_DIR + "preferences.html.template", self.sub_dict)
prefs_fd = open("/usr/share/ipa/html/preferences.html", "w")
prefs_fd.write(prefs_txt)
prefs_fd.close()
# The signing cert is generated in __setup_ssl
- if self.self_signed_ca:
- ca_db = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm)))
- else:
- ca_db = certs.CertDB(NSS_DIR)
db = certs.CertDB(NSS_DIR)
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index f5e0463..c120237 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -210,24 +210,49 @@ def update_file(filename, orig, subst):
print "File %s doesn't exist." % filename
return 1
-def set_directive(filename, directive, value):
+def set_directive(filename, directive, value, quotes=True, separator=' '):
"""Set a name/value pair directive in a configuration file.
This has only been tested with nss.conf
"""
+ valueset = False
fd = open(filename)
file = []
for line in fd:
if directive in line:
- file.append('%s "%s"\n' % (directive, value))
+ valueset = True
+ if quotes:
+ file.append('%s%s"%s"\n' % (directive, separator, value))
+ else:
+ file.append('%s%s%s\n' % (directive, separator, value))
else:
file.append(line)
fd.close()
+ if not valueset:
+ if quotes:
+ file.append('%s%s"%s"\n' % (directive, separator, value))
+ else:
+ file.append('%s%s%s\n' % (directive, separator, value))
fd = open(filename, "w")
fd.write("".join(file))
fd.close()
+def get_directive(filename, directive, strip_quotes=True, separator=' '):
+ """
+ A rather inefficient way to get a configuration directive.
+ """
+ fd = open(filename, "r")
+ for line in fd:
+ if directive in line:
+ line = line.strip()
+ result = line.split(separator, 1)[1]
+ result = result.strip('"')
+ fd.close()
+ return result
+ fd.close()
+ return None
+
def kadmin(command):
ipautil.run(["/usr/kerberos/sbin/kadmin.local", "-q", command])