User-defined certificate subjects

Let the user, upon installation, set the certificate subject base
for the dogtag CA. Certificate requests will automatically be given
this subject base, regardless of what is in the CSR.

The selfsign plugin does not currently support this dynamic name
re-assignment and will reject any incoming requests that don't
conform to the subject base.

The certificate subject base is stored in cn=ipaconfig but it does
NOT dynamically update the configuration, for dogtag at least. The
file /var/lib/pki-ca/profiles/ca/caIPAserviceCert.cfg would need to
be updated and pki-cad restarted.
This commit is contained in:
Rob Crittenden 2010-01-20 11:26:20 -05:00
parent 2955c955ac
commit e4470f8165
11 changed files with 164 additions and 46 deletions

View File

@ -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) )

View File

@ -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",

View File

@ -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"

View File

@ -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")

View File

@ -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):

View File

@ -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",

View File

@ -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):

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()