summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/share/60ipaconfig.ldif4
-rwxr-xr-xinstall/tools/ipa-replica-install8
-rwxr-xr-xinstall/tools/ipa-replica-prepare31
-rwxr-xr-xinstall/tools/ipa-server-install39
-rw-r--r--ipalib/plugins/config.py18
-rw-r--r--ipaserver/install/cainstance.py28
-rw-r--r--ipaserver/install/certs.py25
-rw-r--r--ipaserver/install/dsinstance.py9
-rw-r--r--ipaserver/install/httpinstance.py11
-rw-r--r--ipaserver/install/service.py8
-rw-r--r--ipaserver/plugins/selfsign.py29
11 files changed, 164 insertions, 46 deletions
diff --git a/install/share/60ipaconfig.ldif b/install/share/60ipaconfig.ldif
index 3411e2c4..8cf211e9 100644
--- a/install/share/60ipaconfig.ldif
+++ b/install/share/60ipaconfig.ldif
@@ -39,9 +39,11 @@ attributeTypes: ( 2.16.840.1.113730.3.8.3.51 NAME 'ipaEscrowKeyCertificate' DESC
attributeTypes: ( 2.16.840.1.113730.3.8.3.52 NAME 'ipaEscrowKey' DESC 'PKCS#12-formatted encrypted certificate and private key for encrypting escrow packets' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5)
# ipaMigrationEnabled - if TRUE allow adding user entries with pre-hashed passwords
attributeTypes: ( 2.16.840.1.113730.3.8.1.16 NAME 'ipaMigrationEnabled' DESC 'Enable adding user entries with pre-hashed passwords.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+attributetypes: ( 2.16.840.1.113730.3.8.1.14 NAME 'ipaCertificateSubjectBase' S
+YNTAX 1.3.6.1.4.1.1466.115.121.1.15)
###############################################
##
## ObjectClasses
##
## ipaGuiConfig - GUI config parameters objectclass
-objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify $ ipaUserObjectClasses $ ipaGroupObjectClasses $ ipaDefaultEmailDomain $ ipaObsoleteEscrowPacketLifetime $ ipaEscrowKeyCertificate $ ipaEscrowKey $ ipaMigrationEnabled ) )
+objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify $ ipaUserObjectClasses $ ipaGroupObjectClasses $ ipaDefaultEmailDomain $ ipaObsoleteEscrowPacketLifetime $ ipaEscrowKeyCertificate $ ipaEscrowKey $ ipaMigrationEnabled $ ipaCertificateSubjectBase) )
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index 76695786..7131d6b7 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -48,6 +48,7 @@ class ReplicaConfig:
self.host_name = ""
self.repl_password = ""
self.dir = ""
+ self.subject_base = "O=IPA"
def parse_options():
from optparse import OptionParser
@@ -106,6 +107,7 @@ def read_info(dir, rconfig):
rconfig.ds_user = config.get("realm", "ds_user")
rconfig.domain_name = config.get("realm", "domain_name")
rconfig.host_name = config.get("realm", "destination_host")
+ rconfig.subject_base = config.get("realm", "subject_base")
def get_host_name():
hostname = installutils.get_fqdn()
@@ -150,9 +152,8 @@ def install_ca(config):
cs = cainstance.CADSInstance()
cs.create_instance(config.ds_user, config.realm_name, config.host_name, config.domain_name, config.dirman_password)
-
ca = cainstance.CAInstance()
- ca.configure_instance("pkiuser", config.host_name, config.dirman_password, config.dirman_password, pkcs12_info=(cafile,), master_host=config.master_host_name)
+ ca.configure_instance("pkiuser", config.host_name, config.dirman_password, config.dirman_password, pkcs12_info=(cafile,), master_host=config.master_host_name, subject_base=config.subject_base)
return ca
@@ -346,6 +347,8 @@ def main():
CA.import_ra_cert(dir + "/ra.p12")
CA.fix_ra_perms()
service.restart("httpd")
+ service.print_msg("Setting the certificate subject base")
+ CA.set_subject_in_config(util.realm_to_suffix(config.realm_name))
# The DS instance is created before the keytab, add the SSL cert we
# generated
@@ -370,6 +373,7 @@ def main():
service.restart("dirsrv")
service.restart("krb5kdc")
+ service.restart("httpd")
if options.setup_dns:
api.Backend.ldap2.connect(bind_dn="cn=Directory Manager",
diff --git a/install/tools/ipa-replica-prepare b/install/tools/ipa-replica-prepare
index bc86a41a..f9977ecb 100755
--- a/install/tools/ipa-replica-prepare
+++ b/install/tools/ipa-replica-prepare
@@ -33,6 +33,7 @@ from ipaserver import ipaldap
from ipapython import version
from ipalib.constants import DEFAULT_CONFIG
from ipalib import api
+from ipalib import util
import ldap
def parse_options():
@@ -94,13 +95,23 @@ def get_domain_name():
return domain_name
+def get_subject_base(host_name, dm_password, suffix):
+ try:
+ conn = ipaldap.IPAdmin(host_name)
+ conn.do_simple_bind(bindpw=dm_password)
+ except Exception, e:
+ logging.critical("Could not connect to the Directory Server on %s" % host_name)
+ raise e
+ entry = conn.getEntry("cn=ipaConfig, cn=etc, %s" % suffix, ldap.SCOPE_SUBTREE)
+ return entry.getValue('ipacertificatesubjectbase')
+
def check_ipa_configuration(realm_name):
config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
if not ipautil.dir_exists(config_dir):
logging.error("could not find directory instance: %s" % config_dir)
sys.exit(1)
-def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, hostname):
+def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, hostname, subject_base=None):
"""realm is the kerberos realm for the IPA server.
ds_dir is the location of the master DS we are creating a replica for.
dir is the location of the files for the replica we are creating.
@@ -113,14 +124,14 @@ def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, hostname):
try:
self_signed = certs.ipa_self_signed()
- db = certs.CertDB(dir)
+ db = certs.CertDB(dir, subject_base=subject_base)
db.create_passwd_file()
# if self_signed:
# ca_db = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name)))
# db.create_from_cacert(ca_db.cacert_fname)
# else:
# ca_db = certs.CertDB(httpinstance.NSS_DIR, host_name=get_host_name())
- ca_db = certs.CertDB(httpinstance.NSS_DIR, host_name=get_host_name())
+ ca_db = certs.CertDB(httpinstance.NSS_DIR, host_name=get_host_name(), subject_base=subject_base)
db.create_from_cacert(ca_db.cacert_fname)
db.create_server_cert("Server-Cert", hostname, ca_db)
except Exception, e:
@@ -174,7 +185,8 @@ def get_ds_user(ds_dir):
return user
-def save_config(dir, realm_name, host_name, ds_user, domain_name, dest_host):
+def save_config(dir, realm_name, host_name, ds_user, domain_name, dest_host,
+ subject_base):
config = SafeConfigParser()
config.add_section("realm")
config.set("realm", "realm_name", realm_name)
@@ -182,6 +194,7 @@ def save_config(dir, realm_name, host_name, ds_user, domain_name, dest_host):
config.set("realm", "ds_user", ds_user)
config.set("realm", "domain_name", domain_name)
config.set("realm", "destination_host", dest_host)
+ config.set("realm", "subject_base", subject_base)
fd = open(dir + "/realm_info", "w")
config.write(fd)
@@ -265,6 +278,8 @@ def main():
print "Preparing replica for %s from %s" % (replica_fqdn, host_name)
+ subject_base = get_subject_base(host_name, dirman_password, util.realm_to_suffix(realm_name))
+
top_dir = tempfile.mkdtemp("ipa")
dir = top_dir + "/realm_info"
os.mkdir(dir, 0700)
@@ -298,7 +313,7 @@ def main():
print "Copy failed %s" % e
sys.exit(1)
print "Creating SSL certificate for the Directory Server"
- export_certdb(realm_name, ds_dir, dir, passwd_fname, "dscert", replica_fqdn)
+ export_certdb(realm_name, ds_dir, dir, passwd_fname, "dscert", replica_fqdn, subject_base)
if options.http_pin:
passwd = options.http_pin
@@ -319,13 +334,15 @@ def main():
sys.exit(1)
else:
print "Creating SSL certificate for the Web Server"
- export_certdb(realm_name, ds_dir, dir, passwd_fname, "httpcert", replica_fqdn)
+ export_certdb(realm_name, ds_dir, dir, passwd_fname, "httpcert", replica_fqdn, subject_base)
print "Exporting RA certificate"
export_ra_pkcs12(dir, dirman_password)
+
print "Copying additional files"
copy_files(realm_name, dir)
+
print "Finalizing configuration"
- save_config(dir, realm_name, host_name, ds_user, domain_name, replica_fqdn)
+ save_config(dir, realm_name, host_name, ds_user, domain_name, replica_fqdn, subject_base)
replicafile = "/var/lib/ipa/replica-info-" + replica_fqdn
encfile = replicafile+".gpg"
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index c92989a4..06bed03b 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -35,6 +35,7 @@ import signal
import shutil
import glob
import traceback
+import ldap
from optparse import OptionParser
from ConfigParser import RawConfigParser
import random
@@ -49,6 +50,7 @@ from ipaserver.install import certs
from ipaserver.install import service
from ipapython import version
from ipaserver.install.installutils import *
+from ipaserver import ipaldap
from ipapython import sysrestore
from ipapython.ipautil import *
@@ -117,6 +119,8 @@ def parse_options():
help="The starting uid value (default random)")
parser.add_option("--gidstart", dest="gidstart", default=namespace, type=int,
help="The starting gid value (default random)")
+ parser.add_option("--subject", dest="subject", default="O=IPA",
+ help="The certificate subject base (default O=IPA)")
options, args = parser.parse_args()
if not options.setup_dns:
@@ -456,6 +460,20 @@ def render_assets():
ui = ipawebui.create_wsgi_app(api)
ui.render_assets()
+def set_subject_in_config(host_name, dm_password, suffix, subject_base):
+ try:
+ conn = ipaldap.IPAdmin(host_name)
+ conn.do_simple_bind(bindpw=dm_password)
+ except Exception, e:
+ logging.critical("Could not connect to the Directory Server on %s" % host_name)
+ raise e
+ entry = conn.getEntry("cn=ipaConfig, cn=etc, %s" % suffix, ldap.SCOPE_SUBTREE)
+ if entry.getValue('ipaCertificateSubjectBase') is None:
+ newentry = entry.toDict()
+ newentry['ipaCertificateSubjectBase'] = subject_base
+ conn.updateEntry(entry.dn, entry.toDict(), newentry)
+
+ conn.unbind()
def main():
global ds
@@ -502,7 +520,7 @@ def main():
print "Aborting uninstall operation."
sys.exit(1)
- return uninstall(not certs.ipa_self_signed())
+ return uninstall(not certs.ipa_self_signed() or options.ca)
# This will override any settings passed in on the cmdline
options._update_loose(read_cache())
@@ -702,12 +720,12 @@ def main():
cs.create_instance(ds_user, realm_name, host_name, domain_name, dm_password)
ca = cainstance.CAInstance()
if external == 0:
- ca.configure_instance("pkiuser", host_name, dm_password, dm_password)
+ ca.configure_instance("pkiuser", host_name, dm_password, dm_password, subject_base=options.subject)
elif external == 1:
write_cache(options)
- ca.configure_instance("pkiuser", host_name, dm_password, dm_password, csr_file="/root/ipa.csr")
+ ca.configure_instance("pkiuser", host_name, dm_password, dm_password, csr_file="/root/ipa.csr", subject_base=options.subject)
else:
- ca.configure_instance("pkiuser", host_name, dm_password, dm_password, cert_file=options.external_cert_file, cert_chain_file=options.external_ca_file)
+ ca.configure_instance("pkiuser", host_name, dm_password, dm_password, cert_file=options.external_cert_file, cert_chain_file=options.external_ca_file, subject_base=options.subject)
# Configure ntpd
if options.conf_ntp:
@@ -719,11 +737,11 @@ def main():
if options.dirsrv_pkcs12:
pkcs12_info = (options.dirsrv_pkcs12, pw_name)
try:
- ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info)
+ ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info, subject_base=options.subject)
finally:
os.remove(pw_name)
else:
- ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, self_signed_ca=not options.ca, uidstart=options.uidstart, gidstart=options.gidstart)
+ ds.create_instance(ds_user, realm_name, host_name, domain_name, dm_password, self_signed_ca=not options.ca, uidstart=options.uidstart, gidstart=options.gidstart, subject_base=options.subject)
# Create a kerberos instance
krb = krbinstance.KrbInstance(fstore)
@@ -747,10 +765,10 @@ def main():
http = httpinstance.HTTPInstance(fstore)
if options.http_pkcs12:
pkcs12_info = (options.http_pkcs12, pw_name)
- http.create_instance(realm_name, host_name, domain_name, dm_password, autoconfig=False, pkcs12_info=pkcs12_info)
+ http.create_instance(realm_name, host_name, domain_name, dm_password, autoconfig=False, pkcs12_info=pkcs12_info, subject_base=options.subject)
os.remove(pw_name)
else:
- http.create_instance(realm_name, host_name, domain_name, dm_password, autoconfig=True, self_signed_ca=not options.ca)
+ http.create_instance(realm_name, host_name, domain_name, dm_password, autoconfig=True, self_signed_ca=not options.ca, subject_base=options.subject)
ipautil.run(["/sbin/restorecon", "/var/cache/ipa/sessions"])
# Create the management framework config file
@@ -768,6 +786,11 @@ def main():
fd.write('webui_assets_dir=' + ASSETS_DIR + '\n')
fd.close()
+ set_subject_in_config(host_name, dm_password, util.realm_to_suffix(realm_name), options.subject)
+ if options.ca:
+ service.print_msg("Setting the certificate subject base")
+ ca.set_subject_in_config(util.realm_to_suffix(realm_name))
+
# Apply any LDAP updates. Needs to be done after the configuration file
# is created
service.print_msg("Applying LDAP updates")
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index 3030ce7c..a3851e36 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -35,7 +35,7 @@ class config(LDAPObject):
'ipamaxusernamelength', 'ipahomesrootdir', 'ipadefaultloginshell',
'ipadefaultprimarygroup', 'ipadefaultdomain', 'ipasearchtimelimit',
'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields',
- 'ipamigrationenabled',
+ 'ipamigrationenabled', 'ipacertificatesubjectbase',
]
attribute_names = {
'ipamaxusernamelength': 'maximum username length',
@@ -48,52 +48,68 @@ class config(LDAPObject):
'ipausersearchfields': 'search fields for users',
'ipagroupsearchfields': 'search fields for groups',
'ipamigrationenabled': 'enable migration mode',
+ 'ipacertificatesubjectbase': 'base for certificate subjects',
}
takes_params = (
Int('ipamaxusernamelength?',
cli_name='maxusername',
+ label='Max. Username length',
doc='Max. Username length',
minvalue=1,
),
Str('ipahomesrootdir?',
cli_name='homedirectory',
+ label='Home Directory base',
doc='Default location of home directories',
),
Str('ipadefaultloginshell?',
cli_name='defaultshell',
+ label='Default shell',
doc='Default shell for new users',
),
Str('ipadefaultprimarygroup?',
cli_name='defaultgroup',
+ label='Default users group',
doc='Default group for new users',
),
Str('ipadefaultemaildomain?',
cli_name='emaildomain',
+ label='Default e-mail domain',
doc='Default e-mail domain new users',
),
Int('ipasearchtimelimit?',
cli_name='searchtimelimit',
+ label='Search time limit',
doc='Max. amount of time (sec.) for a search (-1 is unlimited)',
minvalue=-1,
),
Int('ipasearchrecordslimit?',
cli_name='searchrecordslimit',
+ label='Search size limit',
doc='Max. number of records to search (-1 is unlimited)',
minvalue=-1,
),
Str('ipausersearchfields?',
cli_name='usersearch',
+ label='User search fields',
doc='A comma-separated list of fields to search when searching for users',
),
Str('ipagroupsearchfields?',
cli_name='groupsearch',
+ label='Group search fields',
doc='A comma-separated list of fields to search when searching for groups',
),
Bool('ipamigrationenabled?',
+ doc='Migration mode',
cli_name='enable_migration',
doc='Enabled migration mode',
),
+ Str('ipacertificatesubjectbase?',
+ label='Certificate Subject base',
+ cli_name='subject',
+ doc='base for certificate subjects (OU=Test,O=Example)',
+ ),
)
def get_dn(self, *keys, **kwargs):
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 97ba833b..47183bb2 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -46,7 +46,6 @@ from ipapython import nsslib
from ipaserver.install import service
from ipaserver.install import installutils
-from ipaserver import ipaldap
from ipaserver.install import dsinstance
from ipalib import util
@@ -414,7 +413,8 @@ class CAInstance(service.Service):
def configure_instance(self, pki_user, host_name, dm_password,
admin_password, ds_port=DEFAULT_DSPORT,
pkcs12_info=None, master_host=None, csr_file=None,
- cert_file=None, cert_chain_file=None):
+ cert_file=None, cert_chain_file=None,
+ subject_base="O=IPA"):
"""Create a CA instance. This may involve creating the pki-ca instance
dogtag instance.
@@ -434,6 +434,7 @@ class CAInstance(service.Service):
if self.pkcs12_info is not None:
self.clone = True
self.master_host = master_host
+ self.subject_base = subject_base
# Determine if we are installing as an externally-signed CA and
# what stage we're in.
@@ -540,7 +541,7 @@ class CAInstance(service.Service):
"-agent_name", "ipa-ca-agent",
"-agent_key_size", "2048",
"-agent_key_type", "rsa",
- "-agent_cert_subject", "\"CN=ipa-ca-agent,O=" + self.domain_name + "\"",
+ "-agent_cert_subject", "\"CN=ipa-ca-agent,%s\"" % self.subject_base,
"-ldap_host", self.host_name,
"-ldap_port", str(self.ds_port),
"-bind_dn", "\"cn=Directory Manager\"",
@@ -553,11 +554,11 @@ class CAInstance(service.Service):
"-backup_pwd", self.admin_password,
"-subsystem_name", self.service_name,
"-token_name", "internal",
- "-ca_subsystem_cert_subject_name", "\"CN=CA Subsystem Certificate,O=" + self.domain_name + "\"",
- "-ca_ocsp_cert_subject_name", "\"CN=OCSP Signing Certificate,O=" + self.domain_name + "\"",
- "-ca_server_cert_subject_name", "CN=" + self.host_name + ",O=" + self.domain_name,
- "-ca_audit_signing_cert_subject_name", "\"CN=CA Audit Signing Certificate,O=" + self.domain_name + "\"",
- "-ca_sign_cert_subject_name", "\"CN=Certificate Authority,O=" + self.domain_name + "\"" ]
+ "-ca_subsystem_cert_subject_name", "\"CN=CA Subsystem,%s\"" % self.subject_base,
+ "-ca_ocsp_cert_subject_name", "\"CN=OCSP Subsystem,%s\"" % self.subject_base,
+ "-ca_server_cert_subject_name", "\"CN=%s,%s\"" % (self.host_name, self.subject_base),
+ "-ca_audit_signing_cert_subject_name", "\"CN=CA Audit,%s\"" % self.subject_base,
+ "-ca_sign_cert_subject_name", "\"CN=Certificate Authority,%s\"" % self.subject_base ]
if self.external == 1:
args.append("-external")
args.append("true")
@@ -770,7 +771,7 @@ class CAInstance(service.Service):
('usertype', "agentType"),
('userstate', "1"),
('userCertificate', decoded),
- ('description', '2;%s;CN=Certificate Authority,O=%s;CN=RA Subsystem Certificate,OU=pki-ipa,O=%s' % (str(self.requestId), self.domain_name, self.domain_name)),]
+ ('description', '2;%s;CN=Certificate Authority,%s;CN=RA Subsystem,%s' % (str(self.requestId), self.subject_base, self.subject_base)),]
ld.add_s(entry_dn, entry)
@@ -886,7 +887,7 @@ class CAInstance(service.Service):
# Generate our CSR. The result gets put into stdout
try:
- (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", "CN=RA Subsystem Certificate,OU=pki-ipa,O=%s" % self.domain_name, "-z", noise_name, "-a"])
+ (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", "CN=RA Subsystem,%s" % self.subject_base, "-z", noise_name, "-a"])
finally:
os.remove(noise_name)
@@ -1000,6 +1001,13 @@ class CAInstance(service.Service):
ipautil.run(["/usr/sbin/semodule", "-i", "/usr/share/selinux/targeted/ipa_dogtag.pp"])
+ def set_subject_in_config(self, suffix):
+ # dogtag ships with an IPA-specific profile that forces a subject
+ # format. We need to update that template with our base subject
+ if installutils.update_file("/var/lib/%s/profiles/ca/caIPAserviceCert.cfg" % PKI_INSTANCE_NAME, 'OU=pki-ipa, O=IPA', self.subject_base):
+ print "Updating subject_base in CA template failed"
+ self.__restart_instance()
+
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 a1dffff2..6e7eb82d 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -173,7 +173,7 @@ def next_replica(serial_file=CA_SERIALNO):
return str(serial)
class CertDB(object):
- def __init__(self, nssdir, fstore=None, host_name=None):
+ def __init__(self, nssdir, fstore=None, host_name=None, subject_base=None):
self.secdir = nssdir
self.noise_fname = self.secdir + "/noise.txt"
@@ -189,13 +189,14 @@ class CertDB(object):
self.certreq_fname = None
self.certder_fname = None
self.host_name = host_name
+ self.cwd = os.getcwd()
self.self_signed_ca = ipa_self_signed()
- if self.self_signed_ca:
- self.subject_format = "CN=%s,ou=test-ipa,O=IPA"
+ if subject_base:
+ self.subject_format = "CN=%%s,%s" % subject_base
else:
- self.subject_format = "CN=%s,OU=pki-ipa,O=IPA"
+ self.subject_format = "CN=%s,O=IPA"
self.cacert_name = "CA certificate"
self.valid_months = "120"
@@ -218,6 +219,10 @@ class CertDB(object):
def __del__(self):
if self.reqdir is not None:
shutil.rmtree(self.reqdir, ignore_errors=True)
+ try:
+ os.chdir(self.cwd)
+ except:
+ pass
def setup_cert_request(self):
"""
@@ -234,6 +239,10 @@ class CertDB(object):
self.certreq_fname = self.reqdir + "/tmpcertreq"
self.certder_fname = self.reqdir + "/tmpcert.der"
+ # When certutil makes a request it creates a file in the cwd, make
+ # sure we are in a unique place when this happens
+ os.chdir(self.reqdir)
+
def set_serial_from_pkcs12(self):
"""A CA cert was loaded from a PKCS#12 file. Set up our serial file"""
@@ -584,6 +593,9 @@ class CertDB(object):
doc.unlink()
conn.close()
+ # base64-decode the result
+ cert = base64.b64decode(cert)
+
# Write the certificate to a file. It will be imported in a later
# step.
f = open(cert_fname, "w")
@@ -670,6 +682,9 @@ class CertDB(object):
doc.unlink()
conn.close()
+ # base64-decode the cert
+ cert = base64.b64decode(cert)
+
f = open(cert_fname, "w")
f.write(cert)
f.close()
@@ -684,8 +699,6 @@ class CertDB(object):
"-t", "u,u,u",
"-i", cert_fname,
"-f", self.passwd_fname]
- if not self.self_signed_ca:
- args.append("-a")
self.run_certutil(args)
def create_pin_file(self):
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 33ff053c..4fcb914c 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -153,7 +153,7 @@ class DsInstance(service.Service):
else:
self.suffix = None
- def create_instance(self, ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info=None, self_signed_ca=False, uidstart=1100, gidstart=1100):
+ def create_instance(self, ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info=None, self_signed_ca=False, uidstart=1100, gidstart=1100, subject_base=None):
self.ds_user = ds_user
self.realm_name = realm_name.upper()
self.serverid = realm_to_serverid(self.realm_name)
@@ -166,6 +166,7 @@ class DsInstance(service.Service):
self.uidstart = uidstart
self.gidstart = gidstart
self.principal = "ldap/%s@%s" % (self.host_name, self.realm_name)
+ self.subject_base = subject_base
self.__setup_sub_dict()
self.step("creating directory server user", self.__create_ds_user)
@@ -328,7 +329,7 @@ class DsInstance(service.Service):
def __enable_ssl(self):
dirname = config_dirname(self.serverid)
- dsdb = certs.CertDB(dirname)
+ dsdb = certs.CertDB(dirname, subject_base=self.subject_base)
if self.pkcs12_info:
dsdb.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1])
server_certs = dsdb.find_server_certs()
@@ -340,7 +341,7 @@ class DsInstance(service.Service):
self.dercert = dsdb.get_cert_from_db(nickname)
else:
nickname = "Server-Cert"
- cadb = certs.CertDB(httpinstance.NSS_DIR, host_name=self.host_name)
+ cadb = certs.CertDB(httpinstance.NSS_DIR, host_name=self.host_name, subject_base=self.subject_base)
if self.self_signed_ca:
cadb.create_self_signed()
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)
@@ -466,7 +467,7 @@ class DsInstance(service.Service):
self.stop()
dirname = config_dirname(realm_to_serverid(self.realm_name))
- certdb = certs.CertDB(dirname)
+ certdb = certs.CertDB(dirname, subject_base=self.subject_base)
if not cacert_name or len(cacert_name) == 0:
cacert_name = "Imported CA"
# we can't pass in the nickname, so we set the instance variable
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index ee62f81f..3ff5cf8a 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -56,7 +56,7 @@ class HTTPInstance(service.Service):
else:
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
- def create_instance(self, realm, fqdn, domain_name, dm_password=None, autoconfig=True, pkcs12_info=None, self_signed_ca=False):
+ def create_instance(self, realm, fqdn, domain_name, dm_password=None, autoconfig=True, pkcs12_info=None, self_signed_ca=False, subject_base=None):
self.fqdn = fqdn
self.realm = realm
self.domain = domain_name
@@ -66,6 +66,7 @@ class HTTPInstance(service.Service):
self.self_signed_ca = self_signed_ca
self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm)
self.dercert = None
+ self.subject_base = subject_base
self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain }
self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl)
@@ -164,10 +165,10 @@ class HTTPInstance(service.Service):
def __setup_ssl(self):
if self.self_signed_ca:
- ca_db = certs.CertDB(NSS_DIR)
+ ca_db = certs.CertDB(NSS_DIR, subject_base=self.subject_base)
else:
- ca_db = certs.CertDB(NSS_DIR, host_name=self.fqdn)
- db = certs.CertDB(NSS_DIR)
+ ca_db = certs.CertDB(NSS_DIR, host_name=self.fqdn, subject_base=self.subject_base)
+ db = certs.CertDB(NSS_DIR, subject_base=self.subject_base)
if self.pkcs12_info:
db.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd="")
server_certs = db.find_server_certs()
@@ -221,7 +222,7 @@ class HTTPInstance(service.Service):
prefs_fd.close()
# The signing cert is generated in __setup_ssl
- db = certs.CertDB(NSS_DIR)
+ db = certs.CertDB(NSS_DIR, subject_base=self.subject_base)
pwdfile = open(db.passwd_fname)
pwd = pwdfile.read()
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 5e2eb63d..5aee093e 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -160,9 +160,15 @@ class Service:
Add a certificate to a service
This should be passed in DER format but we'll be nice and convert
- a base64-encoded cert if needed.
+ a base64-encoded cert if needed (like when we add certs that come
+ from PKCS#12 files.)
"""
try:
+ s = self.dercert.find('-----BEGIN CERTIFICATE-----')
+ if s > -1:
+ e = self.dercert.find('-----END CERTIFICATE-----')
+ s = s + 27
+ self.dercert = self.dercert[s:e]
self.dercert = base64.b64decode(self.dercert)
except Exception:
pass
diff --git a/ipaserver/plugins/selfsign.py b/ipaserver/plugins/selfsign.py
index 7d5dafa7..af832a61 100644
--- a/ipaserver/plugins/selfsign.py
+++ b/ipaserver/plugins/selfsign.py
@@ -38,13 +38,18 @@ if api.env.ra_plugin != 'selfsign':
from ipalib import Backend
from ipalib import errors
from ipalib import x509
+from ipalib import pkcs10
import subprocess
import os
+import re
from ipaserver.plugins import rabase
from ipaserver.install import certs
import tempfile
from pyasn1 import error
from ipalib.request import ugettext as _
+from pyasn1.codec.der import encoder
+import base64
+from ipalib.plugins.cert import get_csr_hostname
class ra(rabase.rabase):
"""
@@ -79,6 +84,28 @@ class ra(rabase.rabase):
.. [2] Base64 encoded
"""
+ try:
+ config = api.Command['config_show']()['result']
+ subject_base = config.get('ipacertificatesubjectbase')[0]
+ hostname = get_csr_hostname(csr)
+ request = pkcs10.load_certificate_request(csr)
+ base = re.split(',\s*(?=\w+=)', subject_base)
+ base.reverse()
+ base.append("CN=%s" % hostname)
+ request_subject = request.get_subject().get_components()
+ new_request = []
+ for r in request_subject:
+ new_request.append("%s=%s" % (r[0], r[1]))
+
+ if str(base).lower() != str(new_request).lower():
+ subject_base='CN=%s, %s' % (hostname, subject_base)
+ new_request.reverse()
+ raise errors.CertificateOperationError(error=_('Request subject \'%s\' does not match the form \'%s\'' % (", ".join(new_request), subject_base)))
+ except errors.CertificateOperationError, e:
+ raise e
+ except Exception, e:
+ raise errors.CertificateOperationError(error=_('unable to decode csr: %s' % e))
+
# certutil wants the CSR to have have a header and footer. Add one
# if it isn't there.
s = csr.find('-----BEGIN NEW CERTIFICATE REQUEST-----')
@@ -86,7 +113,7 @@ class ra(rabase.rabase):
s = csr.find('-----BEGIN CERTIFICATE REQUEST-----')
if s == -1:
csr = '-----BEGIN NEW CERTIFICATE REQUEST-----\n' + csr + \
- '-----END NEW CERTIFICATE REQUEST-----\n'
+ '\n-----END NEW CERTIFICATE REQUEST-----\n'
try:
(csr_fd, csr_name) = tempfile.mkstemp()